kubeadm部署k8s集群
kubeadm部署k8s集群
k8s集群的安装
1.搭建k8s环境平台规划
平台规划
单master集群
多master集群
2.服务器硬件配置要求
测试环境
生产环境
更高要求 16核
3.搭建k8s集群部署方式
①kubeadm
kubeadm是一个K8s部署工具,提供kubeadm init和kubeadm join,用于快速部署Kubernetes集群
官方地址https://kubernetes.io/docs/reference/setup-tools/kubeadm/kubeadm/
②二进制包
从github下载发行版的二进制包,手动部署每个组件,组成Kubernetes集群。推荐使用二进制包的方式搭建k8s。
k8s构建
master: etcd api-server controller-manager scheduler
node: kubelet kube-proxy
kubelet作用: 接收api-server的指令,调用docker启动容器
kube-proxy作用:负载均衡 service
etcd作用: 数据库 yaml kubectl create delete get describe edit
是Kubernetes提供默认的存储系统,保存所有集群数据,使用时需要为etcd数据提供备份计划
scheduler的作用: 调度策略
controller-manager的作用:rc deployment
kubeadm部署k8s集群架构
核心组件:
Add-ons:
组件名称 | 说明 |
---|---|
kube-dns | 负责为整个集群提供DNS服务 |
Ingress Controller | 为服务提供外网入口 |
Heapster | 提供资源监控 |
Dashboard | 提供GUI |
Federation | 提供跨可用区的集群 |
Fluentd-elasticsearch | 提供集群日志采集、存储与查询 |
环境准备
一台或多台机器操作系统 CentOS7.x-86 x64
硬件配置:2GB或更多RAM,2个CPU或更多CPU,硬盘30G或更多
集群中所有机器之间网络互通
可以访问外网,需要拉取镜像
禁止swap分区
10.0.0.11 | k8s-master |
---|---|
10.0.0.12 | k8s-node-1 |
10.0.0.13 | k8s-node-2 |
systemctl stop firewalld
systemctl disable firewalld
sed -i 's/SELINUX=enforcing/SELINUX=disabled/g'/etc/selinux/config
swapoff -a
sed -ri 's/.*swap.*/#&/' /etc/fstab #防止开机自动挂载swap
hostnamectl set-hostname 主机名
sed -i 's/200/IP/g' /etc/sysconfig/network-scripts/ifcfg-eth0
节省iptables4的流量
cat > /etc/sysctl.d/k8s.conf<<EOF
net.bridge.bridge-nf-call-ip6tables=1
net.bridge.bridge-nf-call-iptables=1
EOF
sysctl --system #生效
yum -y install ntpdate 时间同步
ntpdate time.windows.com
master节点
cat > /etc/hosts <<EOF
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
10.0.0.11 k8s-master
10.0.0.12 k8s-node-1
10.0.0.13 k8s-node-2
EOF
scp -rp /etc/hosts root@10.0.0.12:/etc/hosts
scp -rp /etc/hosts root@10.0.0.13:/etc/hosts
master部署
etcd
https://github.com/etcd-io/etcd/releases
- 安装
yum install etcd -y
- 配置
sed -i "6c ETCD_LISTEN_CLIENT_URLS=\"http://0.0.0.0:2379\"" /etc/etcd/etcd.conf
sed -i "21c ETCD_ADVERTISE_CLIENT_URLS=\"http://10.0.0.11:2379\"" /etc/etcd/etcd.conf
sed -i "6c ETCD_LISTEN_CLIENT_URLS=\"http://0.0.0.0:2379\"" /etc/etcd/etcd.conf
sed -i "21c ETCD_ADVERTISE_CLIENT_URLS=\"http://10.0.0.11:2379\"" /etc/etcd/etcd.conf
a [\]text 在指定行后面追加文本,支持使用\n实现多行追加
i [\]text 在行前面插入文本
c [\]text 替换行为单行或多行文本
#[Member] #ETCD_CORS="" ETCD_DATA_DIR="/var/lib/etcd/default.etcd" # 数据文件存放路径 #ETCD_WAL_DIR="" #ETCD_LISTEN_PEER_URLS="http://localhost:2380" # 同类监听地址,用于集群时同步 ETCD_LISTEN_CLIENT_URLS="http://localhost:2379" # 客户端监听地址 #ETCD_MAX_SNAPSHOTS="5" # 快照最大数量 #ETCD_MAX_WALS="5" ETCD_NAME="default" # 服务名,集群时不能一样 ... ... # #[Clustering] #ETCD_INITIAL_ADVERTISE_PEER_URLS="http://localhost:2380" ETCD_ADVERTISE_CLIENT_URLS="http://localhost:2379" ... ...
- 启动并加入开机启动
systemctl start etcd.service
systemctl enable etcd.service
- 检查集群健康状态
etcdctl -C http://10.0.0.11:2379 cluster-health
- etcdctl命令介绍
etcdctl [global options] command [command options] [arguments...]
etcdctl mk [command options] <key> <value>
etcdctl ls [command options] [key]
etcdctl set [command options] <key> <value>
etcdctl get [command options] <key>
backup # 备份etcd目录
cluster-health # 检查etcd群集的运行状况
mk # 生成一个具有给定值的新键
mkdir # 创建新目录
rm # 删除键或目录
rmdir # 删除键。如果是空目录或键值对
get # 检索键的值
ls # 检索目录
set # 设置键的值
setdir # 创建新目录或更新现有目录TTL
update # 使用给定值更新现有密钥
updatedir # 更新现有目录
watch # 观察键的变化
exec-watch # 观察一个键的变化并执行一个可执行文件
member # 成员add、remove和list子命令
user # 用户add、grant和revoke子命令
role # 角色add、grant和revoke子命令
auth # 总体身份验证控制
kubernetes-master
- 安装
yum install kubernetes-master -y
- 配置apiserver
sed -i "8c KUBE_API_ADDRESS=\"--insecure-bind-address=0.0.0.0\"" /etc/kubernetes/apiserver
sed -i "11c KUBE_API_PORT=\"--port=8080\"" /etc/kubernetes/apiserver
sed -i "14c KUBELET_PORT=\"--kubelet-port=10250\"" /etc/kubernetes/apiserver
sed -i "17c KUBE_ETCD_SERVERS=\"--etcd-servers=http://10.0.0.11:2379\"" /etc/kubernetes/apiserver
sed -i "s/ServiceAccount,//" /etc/kubernetes/apiserver
默认配置文件:
### # kubernetes system config # # The following values are used to configure the kube-apiserver # # The address on the local server to listen to. KUBE_API_ADDRESS="--insecure-bind-address=127.0.0.1" # The port on the local server to listen on. # KUBE_API_PORT="--port=8080" # Port minions listen on # KUBELET_PORT="--kubelet-port=10250" # Comma separated list of nodes in the etcd cluster KUBE_ETCD_SERVERS="--etcd-servers=http://127.0.0.1:2379" # Address range to use for services KUBE_SERVICE_ADDRESSES="--service-cluster-ip-range=10.254.0.0/16" # default admission control policies KUBE_ADMISSION_CONTROL="--admission-control=NamespaceLifecycle,NamespaceExists,LimitRanger,SecurityContextDeny,ServiceAccount,ResourceQuota" # Add your own! KUBE_API_ARGS=""
- 配置config
sed -i "22c KUBE_MASTER=\"--master=http://10.0.0.11:8080\"" /etc/kubernetes/config
默认配置文件:
### # kubernetes system config # # The following values are used to configure various aspects of all # kubernetes services, including # # kube-apiserver.service # kube-controller-manager.service # kube-scheduler.service # kubelet.service # kube-proxy.service # logging to stderr means we get it in the systemd journal KUBE_LOGTOSTDERR="--logtostderr=true" # journal message level, 0 is debug KUBE_LOG_LEVEL="--v=0" # Should this cluster be allowed to run privileged docker containers KUBE_ALLOW_PRIV="--allow-privileged=false" # How the controller-manager, scheduler, and proxy find the apiserver KUBE_MASTER="--master=http://127.0.0.1:8080"
- 启动并加入开机启动
systemctl enable kube-apiserver.service
systemctl enable kube-controller-manager.service
systemctl enable kube-scheduler.service
systemctl start kube-apiserver.service
systemctl start kube-controller-manager.service
systemctl start kube-scheduler.service
- 检查服务是否安装正常
[root@k8s-master ~]# kubectl get componentstatus
NAME STATUS MESSAGE ERROR
etcd-0 Healthy {"health":"true"}
scheduler Healthy ok
controller-manager Healthy ok
node部署
kubernetes-node(集成cadvisor)
- 安装
yum install kubernetes-node -y
- 配置config
sed -i "22c KUBE_MASTER=\"--master=http://10.0.0.11:8080\"" /etc/kubernetes/config
- 配置kubelet
sed -i "5c KUBELET_ADDRESS=\"--address=0.0.0.0\"" /etc/kubernetes/kubelet
sed -i "8c KUBELET_PORT=\"--port=10250\"" /etc/kubernetes/kubelet
sed -i "14c KUBELET_API_SERVER=\"--api-servers=http://10.0.0.11:8080\"" /etc/kubernetes/kubelet
k8s-node-1:10.0.0.12
sed -i "11c KUBELET_HOSTNAME=\"--hostname-override=10.0.0.12\"" /etc/kubernetes/kubelet
k8s-node-2:10.0.0.13
sed -i "11c KUBELET_HOSTNAME=\"--hostname-override=10.0.0.13\"" /etc/kubernetes/kubelet
默认配置文件:
### # kubernetes kubelet (minion) config # The address for the info server to serve on (set to 0.0.0.0 or "" for all interfaces) KUBELET_ADDRESS="--address=127.0.0.1" # The port for the info server to serve on # KUBELET_PORT="--port=10250" # You may leave this blank to use the actual hostname KUBELET_HOSTNAME="--hostname-override=127.0.0.1" # location of the api-server KUBELET_API_SERVER="--api-servers=http://127.0.0.1:8080" # pod infrastructure container KUBELET_POD_INFRA_CONTAINER="--pod-infra-container-image=registry.access.redhat.com/rhel7/pod-infrast ructure:latest" # Add your own! KUBELET_ARGS=""
- 启动并加入开机启动
systemctl enable docker
systemctl enable kubelet.service
systemctl enable kube-proxy.service
systemctl start kubelet.service
systemctl start kube-proxy.service
- 在master节点检查
kubectl get nodes
- 访问cadvisor的web界面:
所有节点配置flannel网络
- 安装
yum install flannel -y
- 配置
sed -i 's#127.0.0.1#10.0.0.11#g' /etc/sysconfig/flanneld
- master节点创建key,安装docker启动并加入开机启动
etcdctl mk /atomic.io/network/config '{ "Network": "172.18.0.0/16","Backend": {"Type": "vxlan"} }'
flannel三种模式:
- udp:性能最差
- vxlan:性能较好
- host-gw:性能最好,但云主机不能用
yum install docker -y
systemctl enable docker
systemctl start docker
- 启动并加入开机启动
systemctl enable flanneld.service
systemctl start flanneld.service
docker指定bip设置docker0网卡的IP
- 配置docker服务启动文件:启动时设置iptables规则允许转发
sed -i "/ExecStart=/i ExecStartPost=/usr/sbin/iptables -P FORWARD ACCEPT" /usr/lib/systemd/system/docker.service
systemctl daemon-reload
systemctl restart docker
- 查看flannel网卡
ifconfig flannel0
- 验证各节点互通
docker run -it alpine
ifconfig
- 配置仓库信任和加速
cat > /etc/docker/daemon.json <<EOF
{
"registry-mirrors": ["https://registry.docker-cn.com"],
"insecure-registries": ["10.0.0.11:5000"]
}
EOF
systemctl restart docker
master部署镜像仓库
docker run -d -p 5000:5000 --restart=always --name registry -v /opt/myregistry:/var/lib/registry registry
node提交镜像测试
docker tag alpine:3.9 10.0.0.11:5000/alpine:3.9
docker push 10.0.0.11:5000/alpine:3.9
查看仓库镜像文件
ls /opt/myregistry/docker/registry/v2/repositories
kubernetes集群命令行工具kubectl
kubectl语法格式
kubectl [command] [TYPE] [NAME] [flags]
command:指定要对资源执行的操作,例如create,get,describe和delete
TYPE:指定资源类型,资源类型是大小写敏感的,开发者能够以单数,复数和缩略的形式
例如:
kubectl get pod pod1
kubectl get pods pod1
NAME:指定资源的名称,名称大小写敏感,如果省略名称,则会显示所有的资源,
kubectl get pods
flags:指定可选的参数,例如,可用-s或者-server参数指定Kubernetes API server的地址和端口
kubectl --help获取更多信息
kubectl get --help 具体查看某个操作
#基础命令
create 通过文件名或标准输入创建资源
expose 讲一个资源公开为一个新的Service
run 在集群中运行一个特定的镜像
set 在对象上设置特定的功能
get 显示一个或多个资源
explain 文档参考资料
edit 使用默认的编辑器编辑一个资源
delete 通过文件名,标准输入,资源名称或标签选择器来删除资源
部署和集群管理命令
rollout 管理资源的发布
rolling-update 对给定的复制控制器滚动更新
scale 扩容或缩容Pod数量,Deployment,ReplicaSet,RC或Job
autoscale 创建一个自动选择扩容或缩容并设置Pod数量
certificate 修改证书资源
cluster-info 显示集群信息
top 显示资源(CPU/Memory/Storage)使用,需要Heapster运行;
cordon 标记节点不可调度
uncordon 标记节点可调度
drain 驱逐节点上的应用,准备下线维护
taint 修改节点taint标记
故障和调试命令
describe 显示特定资源或资源组的详细信息
logs 在一个Pod中打印一个容器日志,如果Pod只有一个容器,容器名称是可选的
attach 附加到一个运行的容器
exec 执行命令到容器
port-forward 转发一个或多个本地端口到一个pod
proxy 运行一个proxy到Kubernetes API Server
cp 拷贝文件或目录到容器中
auth 检查授权
#其他命令
高级命令
apply 通过文件名或标准输入对资源应用配置
patch 使用补丁修改,更新资源的字段
replace 通过文件名或标准输入替换一个资源
convert 不同的API版本之间转换配置文件
设置命令
label 更新资源上的标签
annotate 更新资源上的注释
completion 用于实现kubectl工具自动补全
其他命令
api-versions 打印受支持的API版本
config 修改kubeconfig文件(用于访问API,比如配置认证信息)
help 所有命令帮助
plugin 运行一个命令行插件
version 打印客户端和服务版本信息
kubeadm命令详解
--apiserver-advertise-address string #API Server 将要监听的监听地址
--apiserver-bind-port int32 # API Server绑定的端口默认为6443,
--apiserver-cert-extra-sans stringSlice # 可选的证书额外信息,用于指定API Server的服务器证书。可以是IP地址也可以是DNS名称。
--cert-dir string # 证书的存储路径,缺省路径为/etc/kubernetes/pki
--config string #kubeadm配置文件的路径
--ignore-preflight-errors strings #可以忽略检查过程中出现的错误信息,比如忽略swap,如果为all就忽略所有
--image-repository string # 设置一个镜像仓库,默认为k8s.gcr.io
--kubernetes-version string # 选择k8s版本,默认为stable1
--node-name string # 指定node名称
--pod-network-cidr # 设置pod ip地址范围
--service-cidr # 设置service网络地址范围
--service-dns-domain string # 设置域名,默认为cluster.local
--skip-certificate-key-print # 不打印用于加密的key信息
--skip-phases strings # 要跳过哪些阶段
--skip-token-print # 跳过打印token信息
--token # 指定token
--token-ttl #指定token过期时间,默认为24小时,0为永不过期
--upload-certs #更新证书
全局选项
--log-file string #日志路径
--log-file-max-size uint #设置日志文件的最大大小,单位为兆,默认为18000为没有限制rootfs #宿主机的根路径,也就是使用绝对路径
--skip-headers #为true,在log日志里面不显示消息的头部信息
--skip-log-headers #为true在日志文件里面不记录头部信息
YAML文件
资源清单文件
资源编排
1.语法格式
通过缩进表示层级关系
不能使用Tab进行缩进,只能使用空格
一般开头缩进两个空格
字符号后缩进一个空格,比如冒号,逗号等后面
使用---表示新的yaml文件开始
使用#代表注释
2.yaml文件组成部分
控制器定义
被控制对象
3.常用字段含义
4.快速编写yaml文件
第一种使用kubectl create命令生成yaml文件
kubectl create deployment web --image=nginx -o yaml --dry-run > my1.yaml
第二种使用kubectl get命令导出yaml文件
kubectl get deploy
kubectl get deploy nginx -o=yaml --export >my2.yaml
k8s简介
k8s是一个docker集群的管理工具 ,是容器的编排工具
k8s的历史
-
2013年:docker开源,容器
-
2014年 docker容器编排工9999具,立项 谷歌15年运维生产经验borg borg-monitor
-
2015年7月 发布kubernetes 1.0, 加入cncf基金会 孵化
-
2016年,kubernetes干掉两个对手,docker swarm,mesos marathon 1.2版
-
2017年 1.5 -1.9
-
2018年 k8s 从cncf基金会 毕业项目1.10 1.11 1.12
-
2019年: 1.13, 1.14 ,1.15,1.16 1.17
cncf :cloud native compute foundation 孵化器
kubernetes (k8s): 希腊语 舵手,领航者 容器编排领域,
谷歌15年容器使用经验,borg容器管理平台,使用golang重构borg,kubernetes
cncf 基金会 谷歌公司牵头成立
k8s核心功能:
自我修复: 重新启动失败的容器,在节点不可用时,替换和重新调度节点上的容器,对用户定义的健康检查不响应的容器会被中止,并且在容器准备好服务之前不会把其向客户端广播。
弹性伸缩: 通过监控容器的cpu的负载值,如果这个平均高于80%,增加容器的数量;如果这个平均低于10%,减少容器的数量。
服务的自动发现和负载均衡:不需要修改您的应用程序来使用不熟悉的服务发现机制,Kubernetes 为容器提供了自己的 IP 地址和一组容器的单个 DNS 名称,并可以在它们之间进行负载均衡。
滚动升级和一键回滚:
Kubernetes 逐渐部署对应用程序或其配置的更改,同时监视应用程序运行状况,以确保它不会同时终止所有实例。 如果出现问题,Kubernetes会为您恢复更改,利用日益增长的部署解决方案的生态系统。
容器服务升级
1:打包新版本镜像
2:停掉老容器
3:启动新容器
私密配置文件管理 web容器里面,数据库的账户密码(测试库密码)
k8s的安装方式
yum安装 1.5 最容易安装成功,最适合学习的
源码编译安装---难度最大 可以安装最新版
二进制安装---步骤繁琐 可以安装最新版 shell,ansible,saltstack,适合生产
kubeadm 安装最容易, 网络 可以安装最新版 适合生产
minikube 适合开发人员体验k8s, 国外网络
k8s最适合跑微服务项目!
微服务:mvc架构
mvc业务:只有一套架构集群
软件开发架构:model viewer controller
微服务架构:拆业务
N+套架构
微服务架构:支持更多的并发,网站高可用性更强,业务更加健壮,代码更新更快
京东 订单 快递员的轨迹
微服务架构-------拆成100个业务
java tomcat | java tomcat
消息队列 RabbitMQ kafka redis
虚拟机:物理机
300套:tomcat
docker tomcat + code
k8s开机检查
kubectl get componentstatus
kubectl get nodes
kubectl get pod -o wide
[root@k8s-master ~]# kubectl get componentstatus # 检查组件状态
NAME STATUS MESSAGE ERROR
etcd-0 Healthy {"health":"true"}
scheduler Healthy ok
controller-manager Healthy ok
[root@k8s-master ~]# kubectl get nodes # 检查nodes节点状态
NAME STATUS AGE
10.0.0.12 Ready 21m
10.0.0.13 Ready 3d
[root@k8s-master ~]# kubectl get pod -o wide # 检查pod节点状态
NAME READY STATUS RESTARTS AGE IP NODE
nginx-8phch 1/1 Running 1 13h 172.18.100.2 10.0.0.13
nginx-dc8wc 1/1 Running 1 13h 172.18.100.3 10.0.0.13
nginx-kcmpv 1/1 Running 1 13h 172.18.100.4 10.0.0.13
nginx-mknrb 1/1 Running 1 13h 172.18.100.6 10.0.0.13
nginx-zk9kg 1/1 Running 0 8s 172.18.68.2 10.0.0.12
[root@k8s-master ~]# ping 172.18.100.2
PING 172.18.100.2 (172.18.100.2) 56(84) bytes of data.
64 bytes from 172.18.100.2: icmp_seq=1 ttl=63 time=3.82 ms
64 bytes from 172.18.100.2: icmp_seq=2 ttl=63 time=0.380 ms
^C
--- 172.18.100.2 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1001ms
rtt min/avg/max/mdev = 0.380/2.104/3.829/1.725 ms
[root@k8s-master ~]# ping 172.18.68.2
PING 172.18.68.2 (172.18.68.2) 56(84) bytes of data.
64 bytes from 172.18.68.2: icmp_seq=1 ttl=63 time=2.48 ms
64 bytes from 172.18.68.2: icmp_seq=2 ttl=63 time=0.354 ms
^C
--- 172.18.68.2 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1002ms
rtt min/avg/max/mdev = 0.354/1.421/2.488/1.067 ms
k8s资源
创建pod
资源
准备:
node下载镜像,上传至私有仓库
docker pull nginx:1.13
docker tag docker.io/nginx:1.13 10.0.0.11:5000/nginx:1.13
docker push 10.0.0.11:5000/nginx:1.13
docker pull nginx:1.15
docker tag docker.io/nginx:1.15 10.0.0.11:5000/nginx:1.15
docker push 10.0.0.11:5000/nginx:1.15
docker pull alpine
docker tag docker.io/alpine:latest 10.0.0.11:5000/alpine:latest
docker push 10.0.0.11:5000/alpine:latest
注:解决软连接失效的问题
安装pod-infrastructure
重启 systemctl restart kube-scheduler.service
pod资源和容器的关系
Pod(容器组)是 Kubernetes 中最小的调度单元,可以通过 yaml 定义文件直接创建一个 Pod。但 Pod 本身并不具备自我恢复(self-healing)功能。如果一个 Pod 所在的节点出现故障,或者调度程序自身出现问题,以及节点资源不够或节点进入维护而驱逐 Pod 时,Pod 将被删除,且不能自我恢复。
pod
最小部署单元
包含多个容器(一组容器的集合)
一个pod中容器共享网络命名空间
pod的生命周期是短暂的
创建一个pod
资源,启动了2个容器
一个基础容器pod
一个业务容器nginx
pod存在意义
①创建容器使用docker,一个docker对应一个容器,一个容器有进程,一个容器运行一个应用程序
②pod是多进程程序设计,运行多个应用程序
一个Pod有多个容器,一个容器里面运行一个应用程序
③Pod存在为了亲密性应用
两个应用之间进行交互
网络之间调用
两个应用需要频繁调用
3.Pod实现机制
①共享网络
容器本身之间相互隔离的
namespace
group
前提条件
容器在同一个ns里面
pod实现共享网络机制
pod容器----->info容器
首先创建Pause容器,然后创建业务容器
共享网络:通过Pause容器,把其他业务容器加入到Pause容器里面,让所有业务容器在同一个名称空间中,可以实现网络共享
②共享存储
Pod实现机制 共享存储
pod持久化数据 日志数据 业务数据
共享存储:引入数据卷概念Volumn,使用数据卷进行持久化存储
4Pod镜像拉取策略
IfNotPresent:默认值,镜像在宿主机上不存在时才拉取
Always:每次创建Pod都会重新拉取一次镜像
Never: Pod永远不会主动拉取这个镜像
5.Pod资源限制
6.Pod重启策略
Always: 当容器终止退出后,总是重启容器,默认策略
OnFailure: 当容器异常退出(退出状态码非0)时,才重启容器。
Never: 当容器终止退出,从不重启容器。
7.Pod健康检查
容器检查
java堆内存溢出
应用层面健康检查
livenessProbe(存活检查)
如果检查失败,将杀死容器,根据Pod的restartPolicy来操作
readinessProbe(就绪检查)
如果检查失败,Kubernetes会把Pod从service endpoints中剔除
Probe支持一下三种检查方法:
httpget
发送HTTP请求,返回200-400范围状态码为成功
exec
执行Shell命令返回状态码是0为成功;
tcpsocker
发送 TCP SOCKET 建立成功。.
8.Pod调度策略
创建pod流程
master节点
createpod -- apiserver --etcd
scheduler --apiserver --etcd -- 调度算法,把pod调度某个node节点上
node节点
kublet --apiserver --读取etcd拿到分配给当前节点pod -- docker创建容器
9.Pod调度影响因素
(1)Pod资源限制对Pod调用产生影响
根据request找到足够node节点进行调度
(2)节点选择器标签影响Pod标签
(3)节点亲和性影响Pod调度
节点亲和性 nodeAffinity和之前nodeSelector基本一样的,根据节点上标签约束来绝对Pod调度到哪些节点上
a.硬亲和性
约束条件必须满足
b.软亲和性
尝试满足,不保证
支持常用操作符
In NotIn Exists Gt DoesNotExists
反亲和性
影响pod调度
4.污点和污点容忍
基本介绍
nodeSelector和nodeAffinity: Pod调度到某些节点上,Pod属性,调度时候实现
Taint污点: 节点不做普通分配调度,是节点属性
2.场景
专用场景
配置特点硬件节点
基于Taint驱逐
3.具体演示
(1)查看节点污点情况
污点值有三个
NoSchedule: 一定不被调度
PreferNoSchedule:尽量不被调度
NoExecute: 不会调度,并且还会驱逐Node已有Pod
(2)为节点添加污点
kubectl taint node [node] key=value:污点三个值
(3)删除污点
4.污点容忍
任何一个k8s资源都可以由yml清单文件来定义。
apiVersion: v1 # 版本号
kind: Pod # Pod
metadata: # 元数据
name: string # Pod名称
namespace: string # Pod所属的命名空间
labels: # 自定义标签
- name: string # 自定义标签名字
annotations: # 自定义注释列表
- name: string
spec: # Pod中容器的详细定义
containers: # Pod中容器列表
- name: string # 容器名称
image: string # 容器的镜像名称
imagePullPolicy: [Always | Never | IfNotPresent] # 获取镜像的策略 Alawys表示下载镜像 IfnotPresent表示优先使用本地镜像,否则下载镜像,Nerver表示仅使用本地镜像
command: [string] # 容器的启动命令列表,如不指定,使用打包时使用的启动命令
args: [string] # 容器的启动命令参数列表
workingDir: string # 容器的工作目录
volumeMounts: # 挂载到容器内部的存储卷配置
- name: string # 引用pod定义的共享存储卷的名称,需用volumes[]部分定义的的卷名
mountPath: string # 存储卷在容器内mount的绝对路径,应少于512字符
readOnly: boolean # 是否为只读模式
ports: # 需要暴露的端口库号列表
- name: string # 端口号名称
containerPort: int # 容器需要监听的端口号
hostPort: int # 容器所在主机需要监听的端口号,默认与Container相同
protocol: string # 端口协议,支持TCP和UDP,默认TCP
env: # 容器运行前需设置的环境变量列表
- name: string # 环境变量名称
value: string # 环境变量的值
resources: # 资源限制和请求的设置
limits: # 资源限制的设置
cpu: string #Cpu的限制,单位为core数,将用于docker run --cpu-shares参数
memory: string #内存限制,单位可以为Mib/Gib,将用于docker run --memory参数
requests: # 资源请求的设置
cpu: string # Cpu请求,容器启动的初始可用数量
memory: string # 内存请求,容器启动的初始可用数量
livenessProbe: # 对Pod内个容器健康检查的设置,当探测无响应几次后将自动重启该容器,检查方法有exec、httpGet和tcpSocket,对一个容器只需设置其中一种方法即可
exec: # 对Pod容器内检查方式设置为exec方式
command: [string] # exec方式需要制定的命令或脚本
httpGet: # 对Pod内个容器健康检查方法设置为HttpGet,需要制定Path、port
path: string
port: number
host: string
scheme: string
HttpHeaders:
- name: string
value: string
tcpSocket: # 对Pod内个容器健康检查方式设置为tcpSocket方式
port: number
initialDelaySeconds: 0 # 容器启动完成后首次探测的时间,单位为秒
timeoutSeconds: 0 # 对容器健康检查探测等待响应的超时时间,单位秒,默认1秒
periodSeconds: 0 # 对容器监控检查的定期探测时间设置,单位秒,默认10秒一次
successThreshold: 0
failureThreshold: 0
securityContext:
privileged:false
restartPolicy: [Always | Never | OnFailure] # Pod的重启策略,Always表示一旦不管以何种方式终止运行,kubelet都将重启,OnFailure表示只有Pod以非0退出码退出才重启,Nerver表示不再重启该Pod
nodeSelector: obeject # 设置NodeSelector表示将该Pod调度到包含这个label的node上,以key:value的格式指定
imagePullSecrets: # Pull镜像时使用的secret名称,以key:secretkey格式指定
- name: string
hostNetwork:false # 是否使用主机网络模式,默认为false,如果设置为true,表示使用宿主机网络
volumes: # 在该pod上定义共享存储卷列表
- name: string # 共享存储卷名称 (volumes类型有很多种)
emptyDir: {} # 类型为emtyDir的存储卷,与Pod同生命周期的一个临时目录。为空值
hostPath: string # 类型为hostPath的存储卷,表示挂载Pod所在宿主机的目录
path: string # Pod所在宿主机的目录,将被用于同期中mount的目录
secret: # 类型为secret的存储卷,挂载集群与定义的secre对象到容器内部
scretname: string
items:
- key: string
path: string
configMap: # 类型为configMap的存储卷,挂载预定义的configMap对象到容器内部
name: string
items:
- key: string
path: string
k8s yaml的主要组成:
apiVersion:v1
:api版本kind:pod
:资源类型metadata
:属性spec
:详细
- master节点编写pod资源yaml
mkdir -p /k8s_yml/pod && cd /k8s_yml/pod
cat > /k8s_yml/pod/k8s_pod.yaml <<EOF
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
app: web
spec:
containers:
- name: nginx
image: 10.0.0.11:5000/nginx:1.13
ports:
- containerPort: 80
EOF
- master节点创建资源
kubectl create -f k8s_pod.yaml
- master节点查看所有pod资源状态(集装箱化)
[root@k8s-master pod]# kubectl get pod
NAME READY STATUS RESTARTS AGE
nginx 0/1 ContainerCreating 0 27m
- master节点查看指定pod资源描述(调度至10.0.0.13)
[root@k8s-master pod]# kubectl describe pod nginx
Name: nginx
Namespace: default
Node: 10.0.0.13/10.0.0.13
- node节点(10.0.0.13)搜索缺失镜像并下载,上传至私有仓库
docker search pod-infrastructure
docker pull docker.io/tianyebj/pod-infrastructure
docker tag docker.io/tianyebj/pod-infrastructure:latest 10.0.0.11:5000/pod-infrastructure:latest
docker push 10.0.0.11:5000/pod-infrastructure:latest
- 所有node节点修改配置文件,指定POD下载镜像地址为私有仓库,重启服务
sed -i "17c KUBELET_POD_INFRA_CONTAINER=\"--pod-infra-container-image=10.0.0.11:5000/pod-infrastructure:latest\"" /etc/kubernetes/kubelet
systemctl restart kubelet.service
- master节点再次查看所有pod资源状态(运行中)
[root@k8s-master pod]# kubectl get pod -o wide # -o 显示更宽
NAME READY STATUS RESTARTS AGE IP NODE
nginx 1/1 Running 0 59m 172.18.100.2 10.0.0.13
- node节点(10.0.0.13)查看运行的容器
[root@k8s-node-2 ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
f4a6497de298 10.0.0.11:5000/nginx:1.13 "nginx -g 'daemon ..." 34 minutes ago Up 34 minutes k8s_nginx.91390390_nginx_default_f70dd446-3864-11eb-b602-000c295a6f81_362db3ed
8cf407292934 10.0.0.11:5000/pod-infrastructure:latest "/pod" 34 minutes ago Up 34 minutes k8s_POD.177f01b0_nginx_default_f70dd446-3864-11eb-b602-000c295a6f81_9d56b0b4
[root@k8s-node-2 ~]# docker inspect f4a6497de298 | grep NetworkMode
"NetworkMode": "container:8cf407292934095b3ddabecb197adb33acda43bc38a7ee73a12a681ca30a9a43",
[root@k8s-node-2 ~]# docker inspect 8cf407292934 | grep -A 1 Networks
"Networks": {
"bridge": {
pod资源至少由两个容器组成:基础容器pod和(多个)业务容器nginx组成,共用网络空间。
基础容器pod用于实现k8s高级功能。
- master节点编写pod资源yaml(两个业务容器)
cat > /k8s_yml/pod/k8s_pod2.yaml <<EOF
apiVersion: v1
kind: Pod
metadata:
name: test
labels:
app: web
spec:
containers:
- name: nginx
image: 10.0.0.11:5000/nginx:1.13
ports:
- containerPort: 80
- name: alpine
image: 10.0.0.11:5000/alpine:latest
command: ["sleep","1000"]
EOF
- master节点创建资源
kubectl create -f k8s_pod2.yaml
- master节点查看所有pod资源状态
[root@k8s-master pod]# kubectl get pod
NAME READY STATUS RESTARTS AGE
nginx 1/1 Running 0 2h
test 2/2 Running 1 28m
- node节点(10.0.0.12)查看运行的容器(轮询负载均衡)
[root@k8s-node-1 ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
7bf33f049a9c 10.0.0.11:5000/alpine:latest "sleep 1000" 11 minutes ago Up 11 minutes k8s_alpine.314fe414_test_default_6ef312be-3876-11eb-bf96-000c295a6f81_48c71571
363f874e9d5a 10.0.0.11:5000/nginx:1.13 "nginx -g 'daemon ..." 28 minutes ago Up 28 minutes k8s_nginx.91390390_test_default_6ef312be-3876-11eb-bf96-000c295a6f81_f036679b
d75cc74ef792 10.0.0.11:5000/pod-infrastructure:latest "/pod" 28 minutes ago Up 28 minutes k8s_POD.177f01b0_test_default_6ef312be-3876-11eb-bf96-000c295a6f81_96282638
[root@k8s-node-1 ~]# docker inspect 7bf33f049a9c | grep NetworkMode
"NetworkMode": "container:d75cc74ef79284342d2c31698867a660c404f90a72170729b1f6728514efb84e",
[root@k8s-node-1 ~]# docker inspect 363f874e9d5a | grep NetworkMode
"NetworkMode": "container:d75cc74ef79284342d2c31698867a660c404f90a72170729b1f6728514efb84e",
[root@k8s-node-1 ~]# docker inspect d75cc74ef792 | grep -A 1 Networks
#master 节点
vi k8s_pod2.yml
apiVersion: v1
kind: Pod
metadata:
name: test
labels:
app: web
spec:
containers:
- name: nginx
image: 10.0.0.11:5000/nginx:1.13
ports:
- containerPort: 80
- name: alpine
image: 10.0.0.11:5000/alpine:latest
command: ["sleep","1000"]
ReplicationController资源
rc:保证指定数量的pod始终存活;
rc通过标签选择器来关联pod 不能低于5个
controller
确保周期的副本数量
无状态应用部署
有状态应用部署
确保所有的node运行同一个pod
一次性任务和定时任务
controller
在集群上管理和运行容器的对象
Pod和Controller关系
Pod通过Controller实现应用的运维,
比如伸缩,滚动升级等等
Pod和Controller之间通过label标签建立关系
selector
3.deployment应用场景
部署无状态应用
管理Pod和ReplicaSet
部署,滚动升级等功能
应用场景
web服务,微服务
4.使用deployment部署应用(yaml)
第一步:导出yaml文件
第二步:使用yaml部署应用
第三步:对外发布(暴露对外端口号)
1.master节点编写ReplicationController资源yaml
mkdir /k8s_yml/rc -p && cd /k8s_yml/rc
tee /k8s_yml/rc/k8s_rc.yml <<-EOF
apiVersion: v1
kind: ReplicationController
metadata:
name: nginx
spec:
replicas: 5 #副本5
selector:
app: myweb
template: #模板
metadata:
labels:
app: myweb
spec:
containers:
- name: myweb
image: 10.0.0.11:5000/nginx:1.13
ports:
- containerPort: 80
EOF
- master节点创建资源(5个pod)
kubectl create -f k8s_rc.yaml
- master节点查看资源状态
[root@k8s-master rc]# kubectl get rc
NAME DESIRED CURRENT READY AGE
nginx 5 5 5 6s
[root@k8s-master rc]# kubectl get pod
NAME READY STATUS RESTARTS AGE
nginx 1/1 Running 0 2h
nginx-2w6fb 1/1 Running 0 1m
nginx-35m8t 1/1 Running 0 1m
nginx-7xhms 1/1 Running 0 1m
nginx-kxljm 1/1 Running 0 1m
nginx-sv4d5 1/1 Running 0 1m
test 2/2 Running 2 38m
rc保证指定数量的pod始终存活
- master节点删除一个pod,再查看资源状态:仍然有5个pod
[root@k8s-master rc]# kubectl delete pod nginx-2w6fb
pod "nginx-2w6fb" deleted
[root@k8s-master rc]# kubectl get pod
NAME READY STATUS RESTARTS AGE
nginx 1/1 Running 0 2h
nginx-35m8t 1/1 Running 0 2m
nginx-5mbbq 1/1 Running 0 4s
nginx-7xhms 1/1 Running 0 2m
nginx-kxljm 1/1 Running 0 2m
nginx-sv4d5 1/1 Running 0 2m
test 2/2 Running 2 38m
[root@k8s-master rc]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE
nginx 1/1 Running 0 2h 172.18.100.2 10.0.0.13
nginx-35m8t 1/1 Running 0 6m 172.18.100.3 10.0.0.13
nginx-5mbbq 1/1 Running 0 4m 172.18.68.5 10.0.0.12
nginx-7xhms 1/1 Running 0 6m 172.18.100.4 10.0.0.13
nginx-kxljm 1/1 Running 0 6m 172.18.68.3 10.0.0.12
nginx-sv4d5 1/1 Running 0 6m 172.18.100.5 10.0.0.13
test 2/2 Running 2 43m 172.18.68.2 10.0.0.12
- 关闭一个node节点(10.0.0.12)(等2分钟)
systemctl stop kubelet.service
- master节点查看到一个node节点离线,移除该节点
[root@k8s-master rc]# kubectl get node
NAME STATUS AGE
10.0.0.12 NotReady 3d
10.0.0.13 Ready 3d
[root@k8s-master rc]# kubectl delete node 10.0.0.12
node "10.0.0.12" deleted
- master节点查看资源状态(rc资源自动迁移)
[root@k8s-master rc]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE
nginx 1/1 Running 0 2h 172.18.100.2 10.0.0.13
nginx-35m8t 1/1 Running 0 10m 172.18.100.3 10.0.0.13
nginx-7xhms 1/1 Running 0 10m 172.18.100.4 10.0.0.13
nginx-dhcxr 1/1 Running 0 7s 172.18.100.7 10.0.0.13
nginx-jqhr9 1/1 Running 0 7s 172.18.100.6 10.0.0.13
nginx-sv4d5 1/1 Running 0 10m 172.18.100.5 10.0.0.13
rc通过标签选择器来关联pod
- master节点删除一个pod
kubectl delete pod nginx-35m8t
使用
--all
参数删除所有指定种类资源kubectl delete pod --all
- master节点查看标签
[root@k8s-master rc]# kubectl get pod --show-labels
NAME READY STATUS RESTARTS AGE LABELS
nginx 1/1 Running 0 2h app=web
nginx-7xhms 1/1 Running 0 14m app=myweb
nginx-ccxz2 1/1 Running 0 11s app=myweb
nginx-dhcxr 1/1 Running 0 4m app=myweb
nginx-jqhr9 1/1 Running 0 4m app=myweb
nginx-sv4d5 1/1 Running 0 14m app=myweb
[root@k8s-master rc]# kubectl get rc -o wide
NAME DESIRED CURRENT READY AGE CONTAINER(S) IMAGE(S) SELECTOR
nginx 5 5 5 13m myweb 10.0.0.11:5000/nginx:1.13 app=myweb
- 修改nginx的标签为
app: myweb
,自动删除最年轻的pod资源,保持5个
[root@k8s-master rc]# kubectl edit pod nginx
[root@k8s-master rc]# kubectl get pod --show-labels
NAME READY STATUS RESTARTS AGE LABELS
nginx 1/1 Running 0 2h app=myweb
nginx-7xhms 1/1 Running 0 16m app=myweb
nginx-dhcxr 1/1 Running 0 5m app=myweb
nginx-jqhr9 1/1 Running 0 5m app=myweb
nginx-sv4d5 1/1 Running 0 16m app=myweb
rc滚动升级
- 根据k8s_rc2.yaml创建升级k8s_rc2.yaml,修改:
name
app
image
cat > /k8s_yml/rc/k8s_rc2.yaml <<EOF
apiVersion: v1
kind: ReplicationController
metadata:
name: nginx2
spec:
replicas: 5
selector:
app: myweb2
template:
metadata:
labels:
app: myweb2
spec:
containers:
- name: myweb2
image: 10.0.0.11:5000/nginx:1.15
ports:
- containerPort: 80
EOF
- 升级(5s一个)
kubectl rolling-update nginx -f k8s_rc2.yaml --update-period=5s
[root@k8s-master rc]# kubectl rolling-update nginx -f k8s_rc2.yaml --update-period=5s
Created nginx2
Scaling up nginx2 from 0 to 5, scaling down nginx from 5 to 0 (keep 5 pods available, don't exceed 6 pods)
Scaling nginx2 up to 1
Scaling nginx down to 4
Scaling nginx2 up to 2
Scaling nginx down to 3
Scaling nginx2 up to 3
Scaling nginx down to 2
Scaling nginx2 up to 4
Scaling nginx down to 1
Scaling nginx2 up to 5
Scaling nginx down to 0
Update succeeded. Deleting nginx
replicationcontroller "nginx" rolling updated to "nginx2"
[root@k8s-master rc]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE
nginx2-725jx 1/1 Running 0 35s 172.18.100.6 10.0.0.13
nginx2-fhw68 1/1 Running 0 30s 172.18.100.3 10.0.0.13
nginx2-l4b5f 1/1 Running 0 50s 172.18.100.7 10.0.0.13
nginx2-r027f 1/1 Running 0 40s 172.18.100.8 10.0.0.13
nginx2-rkc14 1/1 Running 0 25s 172.18.100.2 10.0.0.13
[root@k8s-master rc]# curl -I 172.18.100.6
HTTP/1.1 200 OK
Server: nginx/1.15.5
Date: Mon, 07 Dec 2020 11:26:46 GMT
Content-Type: text/html
Content-Length: 612
Last-Modified: Tue, 02 Oct 2018 14:49:27 GMT
Connection: keep-alive
ETag: "5bb38577-264"
Accept-Ranges: bytes
- 回滚(1s一个)
kubectl rolling-update nginx2 -f k8s_rc.yaml --update-period=1s
[root@k8s-master rc]# kubectl rolling-update nginx2 -f k8s_rc.yaml --update-period=1s
Created nginx
Scaling up nginx from 0 to 5, scaling down nginx2 from 5 to 0 (keep 5 pods available, don't exceed 6 pods)
Scaling nginx up to 1
Scaling nginx2 down to 4
Scaling nginx up to 2
Scaling nginx2 down to 3
Scaling nginx up to 3
Scaling nginx2 down to 2
Scaling nginx up to 4
Scaling nginx2 down to 1
Scaling nginx up to 5
Scaling nginx2 down to 0
Update succeeded. Deleting nginx2
replicationcontroller "nginx2" rolling updated to "nginx"
[root@k8s-master rc]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE
nginx-4r223 1/1 Running 0 16s 172.18.100.4 10.0.0.13
nginx-8phch 1/1 Running 0 13s 172.18.100.3 10.0.0.13
nginx-dc8wc 1/1 Running 0 15s 172.18.100.2 10.0.0.13
nginx-kcmpv 1/1 Running 0 11s 172.18.100.5 10.0.0.13
nginx-mknrb 1/1 Running 0 9s 172.18.100.6 10.0.0.13
[root@k8s-master rc]# curl -I 172.18.100.6
HTTP/1.1 200 OK
Server: nginx/1.13.12
Date: Mon, 07 Dec 2020 11:33:03 GMT
Content-Type: text/html
Content-Length: 612
Last-Modified: Mon, 09 Apr 2018 16:01:09 GMT
Connection: keep-alive
ETag: "5acb8e45-264"
Accept-Ranges: bytes
Service
service:提供服务的自动发现和负载均衡
service存在意义:
(防止pod失联)(自动发现)
定义一组pod的访问规则(负载均衡)
2.Pod和Service关系
根据label和selector标签建立关联的
通过service实现Pod的负载均衡
Service三种Ip地址类型:
kubectl expose --help
NodePort 、ClusterIP、 LoadBalancer
ClusterIP:集群内部使用
NodePort: 对外访问应用使用
LoadBalancer:对外访问应用使用,公有云
node内网部署应用,外网一般不能访问到的
找到一台可以进行外网访问机器,安装nginx,反向代理
手动把可以访问节点添加到nginx里面
LoadBalancer: 公有云,把负载均衡,控制器
无状态和有状态区别
无状态:
认为Pod都是相同的
没有顺序要求
不用考虑在哪个node运行
随意进行伸缩和扩展
有状态:
上面因素都需要考虑到,
让每个pod独立的,保持pod启动顺序和唯一性
唯一的网络标识符,持久存储
有序,比如mysql主从
部署有状态应用
无头service
ClusterIP: none
(1)Statefulset 部署有状态应用
SatefulSet部署有状态应用必须满足类型是:StatefulSet,
clusterIP:None
查看pod有三个pod,每个都是唯一名称
查看创建无头的service
deployment和statefulset区别:有身份的(唯一标识的)
根据主机名+按照一定规则生成域名
每个pod有唯一主机名
唯一域名
格式: 主机名称 .service名称 名称空间.svc.cluster.local
Pod使用RC(Replication Controller)实现高可用,会出现一些问题:
-
只能在k8s的内部访问,客户端无法访问,因为Pod IP是私有IP地址,外界无法访问。
-
K8s中Node端口映射不可以直接映射到的Pod IP。如果一些Pod死掉了,RC就会创建一些新的Pod,新的Pod的ip地址会变化,此时做端口映射,修改规则很麻烦。
K8s使用Service资源,kube-proxy服务自动随机分配固定不变的VIP(cluster ip),VIP地址段的范围是10.254.0.0/16。Service资源帮助pod暴露端口。
- master节点编写service资源yaml
mkdir -p /k8s_yml/svc && cd /k8s_yml/svc
cat > /k8s_yml/svc/k8s_svc.yaml <<EOF
apiVersion: v1
kind: Service # 简称svc
metadata:
name: myweb
spec:
type: NodePort # 端口映射类型,默认ClusterIP类型
#clusterIP:10.254.1.1
ports:
- port: 80 # clusterIP port
nodePort: 30000 # node port 默认30000-32767
targetPort: 80 # pod port
selector: # 选择器。当有多个Pod的时候,需要使用选择器选择为那些Pod做负载均衡。和RC一样,使用标签选择器。
app: myweb
EOF
- master节点创建资源
kubectl create -f k8s_svc.yaml
- master节点查看所有svc资源状态
[root@k8s-master svc]# kubectl get svc
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes 10.254.0.1 <none> 443/TCP 3d
myweb 10.254.238.3 <nodes> 80:30000/TCP 4s
[root@k8s-master svc]# kubectl describe svc
Name: kubernetes
Namespace: default
Labels: component=apiserver
provider=kubernetes
Selector: <none>
Type: ClusterIP
IP: 10.254.0.1
Port: https 443/TCP
Endpoints: 10.0.0.11:6443
Session Affinity: ClientIP
No events.
Name: myweb
Namespace: default
Labels: <none>
Selector: app=myweb
Type: NodePort
IP: 10.254.73.4
Port: <unset> 80/TCP
NodePort: <unset> 30000/TCP
Endpoints: 172.18.100.2:80,172.18.100.3:80,172.18.100.4:80 + 2 more...
Session Affinity: None
No events.
- master节点访问node节点端口
[root@k8s-master svc]# curl -I http://10.0.0.12:30000
HTTP/1.1 200 OK
Server: nginx/1.13.12
Date: Tue, 08 Dec 2020 01:19:56 GMT
Content-Type: text/html
Content-Length: 612
Last-Modified: Mon, 09 Apr 2018 16:01:09 GMT
Connection: keep-alive
ETag: "5acb8e45-264"
Accept-Ranges: bytes
[root@k8s-master svc]# curl -I http://10.0.0.13:30000
HTTP/1.1 200 OK
Server: nginx/1.13.12
Date: Tue, 08 Dec 2020 01:19:56 GMT
Content-Type: text/html
Content-Length: 612
Last-Modified: Mon, 09 Apr 2018 16:01:09 GMT
Connection: keep-alive
ETag: "5acb8e45-264"
Accept-Ranges: bytes
service提供负载均衡
- master节点调整rc副本数量
kubectl scale rc nginx --replicas=3
- master节点进入3个pod容器,修改容器的首页为不同页面
kubectl get pod
kubectl exec -it pod_name1 /bin/bash
echo 'web01' > /usr/share/nginx/html/index.html
exit
kubectl exec -it pod_name2 /bin/bash
echo 'web02' > /usr/share/nginx/html/index.html
exit
kubectl exec -it pod_name3 /bin/bash
echo 'web03' > /usr/share/nginx/html/index.html
exit
pod中有多个业务容器,使用参数
--container
进入指定业务容器kubectl exec --container=alpine -it test /bin/sh
- master节点验证负载均衡
[root@k8s-master svc]# i=1;while ((i<=3));do curl http://10.0.0.12:30000;sleep 2;((i++));done
web02
web03
web01
service默认使用iptables实现四层负载均衡。
k8s 1.8版本推荐使用lvs(四层负载均衡 传输层tcp,udp)
service提供服务的自动发现
- master节点调整rc副本数量为2,查看pod
kubectl scale rc nginx --replicas=2
kubectl get pod
- master节点调整rc副本数量为3,查看pod
kubectl scale rc nginx --replicas=3
kubectl get pod
自定义nodePort范围
sed -i "26c KUBE_API_ARGS=\"--service-node-port-range=3000-50000\"" /etc/kubernetes/apiserver
systemctl restart kube-apiserver.service
命令行创建service资源(node端口只能随机)
kubectl expose rc nginx --type=NodePort --port=80 --target-port=80
service类型
第一种:NodePort类型
type: NodePort
ports:
- port: 80
targetPort: 80
nodePort: 30008
第二种:ClusterIP类型,默认
type: ClusterIP
ports:
- port: 80
targetPort: 80
Deployment
rc在滚动升级之后,标签改变,但service却无法跟着改变,会造成服务访问中断,于是k8s引入了deployment资源。
- master节点编写deployment资源yaml
mkdir -p /k8s_yml/deploy && cd /k8s_yml/deploy
cat > /k8s_yml/deploy/k8s_deploy.yaml <<EOF
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: nginx
spec:
replicas: 3
strategy: # 策略
rollingUpdate: # 滚动升级
maxSurge: 1 # 多启动几个容器
maxUnavailable: 1 # 最大不可用的pod数量
type: RollingUpdate
minReadySeconds: 30 # 升级间隔最小秒
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: 10.0.0.11:5000/nginx:1.13
ports:
- containerPort: 80
resources: # 资源
limits: # 限制
cpu: 100m
memory: 50Mi
requests:
cpu: 100m
memory: 50Mi
EOF
- master节点创建资源
kubectl create -f k8s_deploy.yaml
- master节点查看资源状态
[root@k8s-master deploy]# kubectl get deployment
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
nginx 3 3 3 0 3s
[root@k8s-master deploy]# kubectl get pod --show-labels
NAME READY STATUS RESTARTS AGE LABELS
nginx-2807576163-3550z 1/1 Running 0 4s app=nginx,pod-template-hash=2807576163
nginx-2807576163-bmxmz 1/1 Running 0 4s app=nginx,pod-template-hash=2807576163
nginx-2807576163-pt83k 1/1 Running 0 4s app=nginx,pod-template-hash=2807576163
nginx-8phch 1/1 Running 1 15h app=myweb
nginx-dc8wc 1/1 Running 1 15h app=myweb
nginx-twk24 1/1 Running 0 1h app=myweb
[root@k8s-master deploy]# kubectl get all--
deployment滚动升级
deployment滚动升级不依赖配置文件,服务访问不中断;修改配置文件立即生效。
deployment升级时:更新了Pod,通过创建一个新的Replica Set(rc的升级版)并扩容3个replica,同时将原来的Replica Set缩容到0个replica。
下次更新这些pod的时候,只需要更新Deployment中的pod的template即可。
Deployment可以保证在升级时只有一定数量的Pod是down的。默认maxUnavailable: 1(最多一个不可用)。
Deployment同时也可以确保只创建出超过期望数量的一定数量的Pod。默认maxSurge: 1(最多1个surge)。
- 命令行创建service资源
kubectl expose deploy nginx --type=NodePort --port=80 --target-port=80
- 查看service资源映射node端口
[root@k8s-master deploy]# kubectl get svc
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes 10.254.0.1 <none> 443/TCP 3d
myweb 10.254.73.4 <nodes> 80:30000/TCP 1h
nginx 10.254.185.133 <nodes> 80:31504/TCP 19s
- 升级:修改deployment配置文件。仅需要修改镜像版本
kubectl edit deployment nginx
- 访问验证:升级过程中新老版本可以同时访问
i=1;while ((i<=3));do curl -I 10.0.0.12:31504;sleep 1;((i++));done
deployment升级和回滚
命令行创建deployment(--record 记录版本变更原因)
kubectl run nginx --image=10.0.0.11:5000/nginx:1.13 --replicas=3 --record
命令行滚动升级版本
kubectl set image deployment nginx nginx=10.0.0.11:5000/nginx:1.15
pod中有多个业务容器,指定业务容器名称
alpine=10.0.0.11:5000/alpine:1.15
查看deployment所有历史版本
kubectl rollout history deployment nginx
deployment回滚到上一个版本
kubectl rollout undo deployment nginx
deployment回滚到指定版本
kubectl rollout undo deployment nginx --to-revision=2
间章:练习
k8s中容器之间通过VIP相互访问
tomcat+mysql:2个deployment资源和2个service资源。tomcat访问mysql的svc提供的VIP
- node节点下载镜像,上传至私有仓库
docker pull tomcat-app:v2
docker tag docker.io/kubeguide/tomcat-app:v2 10.0.0.11:5000/tomcat-app:v2
docker push 10.0.0.11:5000/tomcat-app:v2
docker pull mysql:5.7
docker tag docker.io/mysql:5.7 10.0.0.11:5000/mysql:5.7
docker push 10.0.0.11:5000/mysql:5.7
- master节点创建配置文件
mkdir -p /k8s_yml/tomcat_demo && cd /k8s_yml/tomcat_demo
cat > /k8s_yml/tomcat_demo/mysql-rc.yml <<EOF
apiVersion: v1
kind: ReplicationController
metadata:
name: mysql
spec:
replicas: 1
selector:
app: mysql
template:
metadata:
labels:
app: mysql
spec:
containers:
- name: mysql
image: 10.0.0.11:5000/mysql:5.7
ports:
- containerPort: 3306
env:
- name: MYSQL_ROOT_PASSWORD
value: '123456'
EOF
cat > /k8s_yml/tomcat_demo/mysql-svc.yml <<EOF
apiVersion: v1
kind: Service
metadata:
name: mysql
spec:
ports:
- port: 3306
targetPort: 3306
selector:
app: mysql
EOF
cat > /k8s_yml/tomcat_demo/tomcat-rc.yml <<EOF
apiVersion: v1
kind: ReplicationController
metadata:
name: myweb
spec:
replicas: 1
selector:
app: myweb
template:
metadata:
labels:
app: myweb
spec:
containers:
- name: myweb
image: 10.0.0.11:5000/tomcat-app:v2
ports:
- containerPort: 8080
env:
- name: MYSQL_SERVICE_HOST
value: 'mysql'
- name: MYSQL_SERVICE_PORT
value: '3306'
EOF
cat > /k8s_yml/tomcat_demo/tomcat-svc.yml <<EOF
apiVersion: v1
kind: Service
metadata:
name: myweb
spec:
type: NodePort
ports:
- port: 8080
nodePort: 30008
selector:
app: myweb
EOF
- master节点创建mysql的rc和svc资源
kubectl create -f mysql-rc.yml
kubectl create -f mysql-svc.yml
- master节点查看所有svc资源
[root@k8s-master tomcat_demo]# kubectl get svc
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes 10.254.0.1 <none> 443/TCP 3d
mysql 10.254.37.112 <none> 3306/TCP 18s
myweb 10.254.73.4 <nodes> 80:30000/TCP 5h
nginx 10.254.185.133 <nodes> 80:31504/TCP 3h
- master节点删除已有同名svc资源myweb
kubectl delete svc myweb
- master节点修改tomcat的rc资源配置文件,修改变量MYSQL_SERVICE_HOST的值为mysql的VIP
vim tomcat-rc.yml
- master节点创建tomcat的rc和svc资源
kubectl create -f tomcat-rc.yml
kubectl create -f tomcat-svc.yml
资源创建流程
创建pod资源流程:
- 用户和
api-server
交互,使用创建命令kubectl create -f .
api-server
检查yaml文件语法- 错误,报错
- 正确写入etcd数据库
api-server
调用scheduler
- 没有可用node,Pending
- 调度成功,返回name给
api-server
api-server
调用kubelet
,发送pod配置文件
删除pod资源流程:
- 用户和
api-server
交互,使用删除命令kubectl delete pod nginx
api-server
修改etcd数据库中pod的状态api-server
调用kubelet
停止并删除容器- 调用失败,Unkown
- 调用成功,
api-server
删除etcd数据库中pod的记录
创建deployment资源流程:
- 用户和
api-server
交互,使用创建命令kubectl create -f .
api-server
检查yaml文件语法- 错误,报错
- 正确写入etcd数据库
controller-manager
创建rscontroller-manager
申请创建podapi-server
调用scheduler
- 没有可用node,Pending
- 调度成功,返回name给
api-server
api-server
调用kubelet
,发送pod配置文件
部署守护进程DaemonSet
在每个node上运行一个pod,新加入的node也同样运行在一个pod里面
例子:在每个node节点安装数据采集工具
不需要指定副本数,不需要scheduler调度,有几个node节点创建几个,适用于监控,日志收集。
注意:各资源labels不能一致!否则会导致pod一直删除再创建死循环。
mkdir -p /k8s_yml/daemonset && cd /k8s_yml/daemonset
cat > /k8s_yml/daemonset/k8s_daemonset.yaml <<EOF
apiVersion: extensions/v1beta1
kind: DaemonSet
metadata:
name: nginx
spec:
template:
metadata:
labels:
app: oldboy
spec:
containers:
- name: nginx
image: 10.0.0.11:5000/nginx:1.13
ports:
- containerPort: 80
EOF
kubectl create -f k8s_daemonset.yaml
kubectl get pod -o wide
StatefulSet (PetSets)
-
StatefulSet (PetSets):宠物应用,有状态的应用,pod名称固定(有序 01 02 03),适用于数据库应用,redis,ES集群,mysql集群
-
其他资源:畜生应用,无状态的应用,pod名称随机
Jobs
- Jobs:一次性任务,完成状态completed
- Pod:一直运行
cat job.yaml
kubectl create -f job.yaml
kubectl get pods
kubectl get jobs
Cronjobs
Cronjobs:定时任务
cat cronjob.yaml
kubectl apply -f cronjob.yaml
kubectl get pods
kubectl logs 容器名
Ingress
- Ingress:七层负载均衡
- Service:四层负载均衡
Secret
Secret:密码,密钥
作用:加密数据存在etcd里面,让Pod容器以挂载Volume方式进行访问
场景:凭证
echo -n 'admin'|base64
cat secret.yaml
kubectl create -f secret.yaml
kubectl get secret
2.以变量形式挂载到容器中
cat secret-val.yaml
kubectl create -f secret.yaml
kubectl get pods
kubectl exec -it mypod bash
echo $SECRET_USENAME
echo ¥SECRET_PASSWORD
3.以Volume形式挂载pod容器中
cat secret-vol.yaml
kubectl apply -f secret-vol.yaml
kubectl get pods
kubectl exec -it mypod bash
ls /etc/foo
cd /etc/foo
cat password
cat username
Config Maps
Config Maps:配置文件
作用:存储不加密数据到etcd,让Pod以变量或者Volume挂载到容器中
场景:配置文件
1.创建配置文件
kubectl get cm
2.创建configmap
kubectl create configmap redis-config --from-file=redis.properties
kubectl get cs
kubectl describe cs redis-config
3.以Volume挂载到pod容器中
cat cm.yaml
kubectl apply -f cm.yaml
kubectl get pods
#出现completed状态
4.以变量形式挂载到pod容器中
(1)创建yaml,声明变量信息configmap创建
(2)以变量挂载
cat myconfig.yaml
kubectl apply -f myconfig.yaml
kubectl get cm
kubectl logs mypod
k8s集群安全机制
1.概述
(1)访问k8s集群时候,需要经过三个步骤完成具体操作
第一步:认证
第二步:鉴权(授权)
第三步:准入控制
(2)进行访问时候,过程中都需要经过apiserver,apiserver做统一协调,比如门卫。
访问过程中需要证书,token,或者用户名+密码
如果访问pod需要serviceAccount
第一步认证 传输安全
传输安全: 对外不暴露8080端口,只能内部访问,对外使用端口6443
认证:
客户端身份认证常用方式:
https证书认证 基于ca证书
http token认证,通过token识别用户
http基本认证,用户名+密码认证
第二步:鉴权(授权)
基于RBAC进行鉴权操作
基于角色访问控制
第三步:准入控制
就是准入控制器的列表,如果列表有请求内容,通过,没有拒绝。
RBAC
基于角色的访问控制
角色 Role
特定命名空间访问权限
ClusterRole:所有命名空间访问权限
角色绑定
roleBinding:角色绑定到主体
ClusterRoleBinding: 集群角色绑定到主体
主体:
user 用户
group 用户组
serviceAccount 服务账号
1.创建命名空间
kubectl create ns roledemo
2.在新创建的命名空间创建pod
kubectl run nginx --image=nginx -n roledemo
3.创建角色
cat role-rbac.yaml
kubectl apply -f rbac-role.yaml
kubectl get role -n roledemo
4.创建角色绑定
cat rbac-rolebinding.yaml
kubectl apply -f rbac-rolebinding.yaml
kubectl get role.rolebinding -n roledemo
5.使用证书识别身份
cat rabc-user.sh
cp /root/TLS/k8s/ca* ./
bash rabc-user.sh
Ingress
1.把端口号对外暴露,通过ip+端口号进行访问
使用service里面的NodePort实现
2.NodePort缺陷
在每个节点上都会启动端口,在访问时候通过任何节点,通过节点ip+暴露端口号实现访问
意味着每个端口只能使用一次,一个端口对应一个应用
实际访问中都是用域名,根据不同域名跳转到不同端口服务中
3.Ingress和Pod关系
pod和ingress通过service关联的
ingress作为统一入口,由service关联一组pod
ingress 入口
4.ingress工作流程
5.使用ingress
第一步:部署ingress Controller
第二步: 创建ingress规则
选择官方维护nginx控制器,实现部署
6.使用Ingress对外暴露应用
(1)创建nginx应用,对外暴露端口使用NodePort
kubectl create deployment web --image=nginx
kubectl get pods
kubectl get deploy
kubectl expose deployment web --port=80 --target-port=80 --type=NodePort
(2)部署ingress contronller
查看ingress controller状态
kubectl get pods -n ingress-nginx
(3)创建ingress规则
cat ingress-h.yaml
kubectl apply -f ingress-h.yaml
(4)在windows系统hosts文件中添加域名访问规则
10.0.0.11 example.ingredemo.com
helm
1.引入
(1)之前方式部署应用过程
编写yaml文件
deployment
Service
Ingress
如果使用之前方式部署单一应用,少数服务的应用,比较合适
比如部署微服务项目,可能有几十个服务,每个服务都有一套yaml文件,需要维护大量yaml文件,版本管理特别不方便;
2.使用helm能够解决的问题
(1)使用helm可以把这些yaml作为一个整体管理
(2)实现yaml高效复用
(3)使用helm应用级别的版本管理
3.helm介绍
Helm是一个Kubernetes的包管理工具,就像Linux下的包管理工具,如yum/apt等,可以很方便的将之前打包好的yaml文件部署到kubernetes上
4.Helm三个重要概念
(1)helm
是一个命令行客户端工具
(2)Chart
把yaml打包,是yaml的集合
(3)Release
基于chart部署实体,应用级别的版本管理
5.Helm v3变化
helm在2019年发布v3版本,和之前版本相比有变化
(1)V3版本删除Tiller
(2)release 可以在不同命名空间重用
(3)将chart推送到docker仓库中
6.helm架构变化
V3之前版本
V3版本架构
1.helm安装
第一步:下载helm安装压缩文件,上传到linux系统中
wget https://github.com/helm/helm/archive/v3.4.2.tar.gz
第二步: 解压helm压缩文件,把解压之后helm目录复制到usr/bin目录下
tar xf helm-3.4.2.tar.gz
cp -r /root/helm-3.4.2 /usr/bin
2.配置helm仓库
(1)添加仓库
helm repo add 仓库名称 仓库地址
helm repo add
helm repo list
(2)更新仓库地址
helm repo update
(3)删除仓库
helm repo remove aliyun
3.helm快速部署应用
第一步: 使用命令搜索应用
helm search repo 名称 (weave)
第二步:根据搜索内容选择安装
helm install 安装之后名称 搜索之后应用名称
* 查看安装之后状态
helm list
helm status 安装之后名称
helm search repo weave
helm install ui stable/weave-scope #安装
helm status ui
修改service的yaml文件,type改为NodePort
type: NodePort
如何自己创建Chart
1.使用命令创建chart
helm create chart 名称
helm create mychart
Chartyaml: 当前chart属性配置信息
templates: 编写yaml文件放到这个目录中
values.yaml: yaml文件可以使用全局变量
2.在templates文件夹创建两个yaml文件
deployment.yaml
service.yaml
3.安装mycat
helm install web1 mychart/
4.应用升级
helm upgrade chart名称
helm upgrade web1 mychart/
实现yaml高效复用
通过传递参数,动态渲染模板,yaml内容动态传入参数生成
values.yaml
在chart有values.yaml文件,定义yaml文件全局变量
1.在values.yaml定义变量和值
2.在具体yaml文件,获取定义变量值
yaml文件大体有几个不同的
image
tag
label
port
replicas
一.在values.yaml定义变量和值
replicas: 1
image: nginx
tag: 1.16
label: nginx
port: 80
二.在templates的yaml文件使用values.yaml定义变量
通过表达式形式使用全局变量
{{ . Values.变量名称}}
(( .Release .Name))-deploy
数据卷 emptydir,是本地存储,pod重启,数据不存在了,需要对数据持久化存储
nfs,网络存储 pod重启,数据还存在的
第一步:找一台服务器nfs服务端
(1)安装nfs
yum install nfs-utils
(2)设置挂载路径
cat /etc/exports
/data/nfs *{rw.no_root_squash}
(3)挂载路径需要创建出来
mkdir nfs
第二步 在k8s集群node节点安装nfs
yum install nfs-utils
第三步: 在nfs服务器启动nfs服务
systemctl start nfs
ps -ef | grep nfs
第四步: 在k8s集群部署应用使用nfs持久网络存储
cat nfs-nginx.yaml
kubectl apply -f nfs-nginx.yaml
kubectl get pods
kubectl describe
kubectl exec -it nginx-名字 bash
PV和PVC
1.PV:持久化存储,对存储资源进行抽象,对外提供可以调用的地方(生产者)
2.PVC: 用于调用,不需要关心内部实现细节(消费者)
集群资源监控
1.监控指标
集群监控
节点资源利用率
节点数
运行pods
Pod监控
容器指标
应用程序
2.监控平台搭建方案
prometheus+ Grafana
(1)prometheus
开源的
监控,报警,数据库
以HTTP协议周期性抓取被监控组件状态
不需要复杂的集成过程,使用http接口接入就可以了
(2)Grafana
开源的数据分析和可视化工具
支持多种数据源
高可用:
多master
高可用集群技术
master1 master2
1.部署keepalived 1.部署keepalived
2.部署haproxy 2.部署haproxy
3.初始化操作 3.添加master2节点到集群
4.安装docker,网络插件 4.安装docker,网络插件
node1节点
加入到集群中,安装docker,网络插件
资源总结
k8s资源 | 作用 |
---|---|
daemonSet | 用来描述每个宿主机上必须且只能运行一个副本的守护进程服务 |
Job | 用来描述一次性运行的 Pod(比如,大数据任务) |
CronJob | 用于描述定时任务 |
k8s附加组件
DNS服务
DNS服务:将svc的名称解析成对应VIP地址
- node2节点(10.0.0.13)下载镜像,并导入(4个镜像,来自google仓库)
[root@k8s-node-2 ~]# docker load -i docker_k8s_dns.tar.gz
8ac8bfaff55a: Loading layer 1.293 MB/1.293 MB
5f70bf18a086: Loading layer 1.024 kB/1.024 kB
b79219965469: Loading layer 45.91 MB/45.91 MB
Loaded image: gcr.io/google_containers/kubedns-amd64:1.9
3fc666989c1d: Loading layer 5.046 MB/5.046 MB
5f70bf18a086: Loading layer 1.024 kB/1.024 kB
9eed5e14d7fb: Loading layer 348.7 kB/348.7 kB
00dc4ffe8624: Loading layer 2.56 kB/2.56 kB
Loaded image: gcr.io/google_containers/kube-dnsmasq-amd64:1.4
9007f5987db3: Loading layer 5.05 MB/5.05 MB
5f70bf18a086: Loading layer 1.024 kB/1.024 kB
d41159f2130e: Loading layer 9.201 MB/9.201 MB
Loaded image: gcr.io/google_containers/dnsmasq-metrics-amd64:1.0
dc978cfc3e09: Loading layer 7.279 MB/7.279 MB
99740866972b: Loading layer 7.168 kB/7.168 kB
5f70bf18a086: Loading layer 1.024 kB/1.024 kB
Loaded image: gcr.io/google_containers/exechealthz-amd64:1.2
- master节点创建配置文件(指定调度到node2)
mkdir -p /root/k8s_yaml/dns && cd /root/k8s_yaml/dns
cat > /root/k8s_yaml/dns/skydns-svc.yaml <<EOF
# Copyright 2016 The Kubernetes Authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# TODO - At some point, we need to rename all skydns-*.yaml.* files to kubedns-*.yaml.*
# Warning: This is a file generated from the base underscore template file: skydns-svc.yaml.base
apiVersion: v1
kind: Service
metadata:
name: kube-dns
namespace: kube-system
labels:
k8s-app: kube-dns
kubernetes.io/cluster-service: "true"
kubernetes.io/name: "KubeDNS"
spec:
selector:
k8s-app: kube-dns
clusterIP: 10.254.230.254
ports:
- name: dns
port: 53
protocol: UDP
- name: dns-tcp
port: 53
protocol: TCP
EOF
cat > /root/k8s_yaml/dns/skydns.yaml <<EOF
# Copyright 2016 The Kubernetes Authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# TODO - At some point, we need to rename all skydns-*.yaml.* files to kubedns-*.yaml.*
# Should keep target in cluster/addons/dns-horizontal-autoscaler/dns-horizontal-autoscaler.yaml
# in sync with this file.
# __MACHINE_GENERATED_WARNING__
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: kube-dns
namespace: kube-system
labels:
k8s-app: kube-dns
kubernetes.io/cluster-service: "true"
spec:
replicas: 1
# replicas: not specified here:
# 1. In order to make Addon Manager do not reconcile this replicas parameter.
# 2. Default is 1.
# 3. Will be tuned in real time if DNS horizontal auto-scaling is turned on.
strategy:
rollingUpdate:
maxSurge: 10%
maxUnavailable: 0
selector:
matchLabels:
k8s-app: kube-dns
template:
metadata:
labels:
k8s-app: kube-dns
annotations:
scheduler.alpha.kubernetes.io/critical-pod: ''
scheduler.alpha.kubernetes.io/tolerations: '[{"key":"CriticalAddonsOnly", "operator":"Exists"}]'
spec:
nodeName: 10.0.0.13 # 指定调度到的node
containers:
- name: kubedns
image: gcr.io/google_containers/kubedns-amd64:1.9
resources:
# TODO: Set memory limits when we've profiled the container for large
# clusters, then set request = limit to keep this container in
# guaranteed class. Currently, this container falls into the
# "burstable" category so the kubelet doesn't backoff from restarting it.
limits:
memory: 170Mi
requests:
cpu: 100m
memory: 70Mi
livenessProbe:
httpGet:
path: /healthz-kubedns
port: 8080
scheme: HTTP
initialDelaySeconds: 60
timeoutSeconds: 5
successThreshold: 1
failureThreshold: 5
readinessProbe:
httpGet:
path: /readiness
port: 8081
scheme: HTTP
# we poll on pod startup for the Kubernetes master service and
# only setup the /readiness HTTP server once that's available.
initialDelaySeconds: 3
timeoutSeconds: 5
args:
- --domain=cluster.local.
- --dns-port=10053
- --config-map=kube-dns
- --kube-master-url=http://10.0.0.11:8080
# This should be set to v=2 only after the new image (cut from 1.5) has
# been released, otherwise we will flood the logs.
- --v=0
#__PILLAR__FEDERATIONS__DOMAIN__MAP__
env:
- name: PROMETHEUS_PORT
value: "10055"
ports:
- containerPort: 10053
name: dns-local
protocol: UDP
- containerPort: 10053
name: dns-tcp-local
protocol: TCP
- containerPort: 10055
name: metrics
protocol: TCP
- name: dnsmasq
image: gcr.io/google_containers/kube-dnsmasq-amd64:1.4
livenessProbe:
httpGet:
path: /healthz-dnsmasq
port: 8080
scheme: HTTP
initialDelaySeconds: 60
timeoutSeconds: 5
successThreshold: 1
failureThreshold: 5
args:
- --cache-size=1000
- --no-resolv
- --server=127.0.0.1 # 10053
#- --log-facility=-
ports:
- containerPort: 53
name: dns
protocol: UDP
- containerPort: 53
name: dns-tcp
protocol: TCP
# see: https://github.com/kubernetes/kubernetes/issues/29055 for details
resources:
requests:
cpu: 150m
memory: 10Mi
- name: dnsmasq-metrics
image: gcr.io/google_containers/dnsmasq-metrics-amd64:1.0
livenessProbe:
httpGet:
path: /metrics
port: 10054
scheme: HTTP
initialDelaySeconds: 60
timeoutSeconds: 5
successThreshold: 1
failureThreshold: 5
args:
- --v=2
- --logtostderr
ports:
- containerPort: 10054
name: metrics
protocol: TCP
resources:
requests:
memory: 10Mi
- name: healthz
image: gcr.io/google_containers/exechealthz-amd64:1.2
resources:
limits:
memory: 50Mi
requests:
cpu: 10m
# Note that this container shouldn't really need 50Mi of memory. The
# limits are set higher than expected pending investigation on #29688.
# The extra memory was stolen from the kubedns container to keep the
# net memory requested by the pod constant.
memory: 50Mi
args:
- --cmd=nslookup kubernetes.default.svc.cluster.local 127.0.0.1 >/dev/null
- --url=/healthz-dnsmasq
- --cmd=nslookup kubernetes.default.svc.cluster.local 127.0.0.1:10053 >/dev/null
- --url=/healthz-kubedns
- --port=8080
- --quiet
ports:
- containerPort: 8080
protocol: TCP
dnsPolicy: Default # Don't use cluster DNS.
EOF
- master节点创建DNS的资源
kubectl create -f .
- master节点检查命名空间kube-system
kubectl get namespace
kubectl get all -n kube-system -o wide
[root@k8s-master dns]# kubectl get all -n kube-system
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
deploy/kube-dns 1 1 1 1 10m
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
svc/kube-dns 10.254.230.254 <none> 53/UDP,53/TCP 10m
NAME DESIRED CURRENT READY AGE
rs/kube-dns-249145955 1 1 1 10m
NAME READY STATUS RESTARTS AGE
po/kube-dns-249145955-wdmq8 4/4 Running 0 10m
- 所有node节点修改kubelet配置文件,重启服务
sed -i '20c KUBELET_ARGS=\"--cluster_dns=10.254.230.254 --cluster_domain=cluster.local\"' /etc/kubernetes/kubelet
systemctl restart kubelet
- master节点修改tomcat的rc资源配置文件,修改变量MYSQL_SERVICE_HOST的值为mysql,重新创建资源
cd /root/k8s_yaml/tomcat_demo
vim tomcat-rc.yml
kubectl delete -f .
kubectl create -f .
- master节点验证
[root@k8s-master tomcat_demo]# kubectl get pod # 查找myweb容器名
NAME READY STATUS RESTARTS AGE
mysql-sj480 1/1 Running 0 3m
myweb-th9rx 1/1 Running 0 1m
[root@k8s-master tomcat_demo]# kubectl exec -it myweb-th9rx /bin/bash #进入容器
root@myweb-th9rx:/usr/local/tomcat# cat /etc/resolv.conf # 查看DNS解析
search default.svc.cluster.local svc.cluster.local cluster.local
nameserver 10.254.230.254
nameserver 223.5.5.5
options ndots:5
root@myweb-th9rx:/usr/local/tomcat# ping mysql # 能解析,不能ping通,VIP
PING mysql.default.svc.cluster.local (10.254.106.204): 56 data bytes
^C--- mysql.default.svc.cluster.local ping statistics ---
2 packets transmitted, 0 packets received, 100% packet loss
root@myweb-th9rx:/usr/local/tomcat# exit
exit
namespace命名空间
namespace:实现资源隔离
- 查看命名空间
kubectl get namespace
- 创建命名空间
kubectl create namespace tomcat
- 修改配置文件指定命名空间
cd /k8s_yml/tomcat_demo/
sed -i "3a \ \ namespace: tomcat" *
yum install dos2unix -y
dos2unix *
- 删除所有svc和rc资源
kubectl delete svc --all
kubectl delete rc --all
- 创建rc和svc资源
kubectl create -f .
- 查看命名空间tomcat的所有资源
kubectl get all -n tomcat
注:如果出现错误
法一:将四个yml文件修改回去然后删除
kubectl delete -f .
法二:删除资源
kubectl delete svc mysql
kubectl delete svc myweb
kubectl delete rc --all
kubectl delete namespace develop 删除namespace空间
作业
k8s中容器之间通过VIP相互访问,应用DNS,namespace
wordpress+mysql:2个deployment资源和2个service资源。wordpress访问mysql的svc提供的VIP
- node下载镜像,上传至私有仓库
docker pull wordpress
docker tag docker.io/wordpress:latest 10.0.0.11:5000/wordpress:latest
docker push 10.0.0.11:5000/wordpress:latest
docker pull mysql:5.7
docker tag docker.io/mysql:5.7 10.0.0.11:5000/mysql:5.7
docker push 10.0.0.11:5000/mysql:5.7
- 创建rc和svc配置文件
mkdir -p /k8s_yml/wordpress_rc && cd /k8s_yml/wordpress_rc
cat > /k8s_yml/wordpress_rc/mysql-rc.yml <<EOF
apiVersion: v1
kind: ReplicationController
metadata:
namespace: wordpress
name: mysql
spec:
replicas: 1
selector:
app: mysql
template:
metadata:
labels:
app: mysql
spec:
nodeName: 10.0.0.12
containers:
- name: mysql
image: 10.0.0.11:5000/mysql:5.7
ports:
- containerPort: 3306
env:
- name: MYSQL_ROOT_PASSWORD
value: 'root_pwd'
- name: MYSQL_DATABASE
value: 'blog'
- name: MYSQL_USER
value: 'blog'
- name: MYSQL_PASSWORD
value: 'blog'
args:
- --character-set-server=utf8
- --collation-server=utf8_bin
EOF
cat > /k8s_yml/wordpress_rc/mysql-svc.yml <<EOF
apiVersion: v1
kind: Service
metadata:
namespace: wordpress
name: mysql
spec:
ports:
- port: 3306
targetPort: 3306
selector:
app: mysql
EOF
cat > /root/k8s_yaml/wordpress_rc/wordpress-rc.yml <<EOF
apiVersion: v1
kind: ReplicationController
metadata:
namespace: wordpress
name: wordpress
spec:
replicas: 1
selector:
app: wordpress
template:
metadata:
labels:
app: wordpress
spec:
nodeName: 10.0.0.12
containers:
- name: wordpress
image: 10.0.0.11:5000/wordpress:latest
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
env:
- name: WORDPRESS_DB_HOST
value: 'mysql'
- name: WORDPRESS_DB_PASSWORD
value: 'blog'
- name: WORDPRESS_DB_USER
value: 'blog'
- name: WORDPRESS_DB_NAME
value: 'blog'
EOF
cat > /k8s_yml/wordpress_rc/wordpress-svc.yml <<EOF
apiVersion: v1
kind: Service
metadata:
namespace: wordpress
name: wordpress
spec:
type: NodePort
ports:
- port: 80
nodePort: 30080
selector:
app: wordpress
EOF
查看系统补全的配置文件
kubectl get pod NAME -n NAMESPACE -o yaml
镜像下载策略
[root@k8s-master ~]# kubectl explain pod.spec.containers.imagePullPo licy FIELD: imagePullPolicy <string> DESCRIPTION: Image pull policy. One of Always, Never, IfNotPresent. Defaults to Always if :latest tag is specified, or IfNotPresent otherwise. Cannot be updated. More info: http://kubernetes.io/docs/user-guide/images#updating-images Always 总是更新镜像 Never 从不更新镜像 IfNotPresent 如果本地没有,就去pull
- 删除所有资源
kubectl delete svc --all
kubectl delete rc --all
kubectl delete deployment --all
- 创建命名空间
kubectl create namespace wordpress
- 创建资源
kubectl create -f .
- 查看svc资源,访问:http://10.0.0.12:30080/
kubectl get all -n wordpress -o wide
- 创建deploy和svc配置文件
mkdir -p /k8s_yml/wordpress_demo && cd /k8s_yml/wordpress_demo
cat > /k8s_yml/wordpress_demo/mysql-demo.yml <<EOF
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
namespace: wordpress
name: mysql
spec:
replicas: 1
template:
metadata:
labels:
app: mysql
spec:
nodeName: 10.0.0.12
containers:
- name: mysql
image: 10.0.0.11:5000/mysql:5.7
ports:
- containerPort: 3306
env:
- name: MYSQL_ROOT_PASSWORD
value: 'root_pwd'
- name: MYSQL_DATABASE
value: 'blog'
- name: MYSQL_USER
value: 'blog'
- name: MYSQL_PASSWORD
value: 'blog'
args:
- --character-set-server=utf8
- --collation-server=utf8_bin
EOF
cat > /k8s_yml/wordpress_demo/mysql-svc.yml <<EOF
apiVersion: v1
kind: Service
metadata:
namespace: wordpress
name: mysql
spec:
ports:
- port: 3306
targetPort: 3306
selector:
app: mysql
EOF
cat > /k8s_yml/wordpress_demo/wordpress-demo.yml <<EOF
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
namespace: wordpress
name: wordpress
spec:
replicas: 1
template:
metadata:
labels:
app: wordpress
spec:
nodeName: 10.0.0.12
containers:
- name: wordpress
image: 10.0.0.11:5000/wordpress:latest
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
env:
- name: WORDPRESS_DB_HOST
value: 'mysql'
- name: WORDPRESS_DB_PASSWORD
value: 'blog'
- name: WORDPRESS_DB_USER
value: 'blog'
- name: WORDPRESS_DB_NAME
value: 'blog'
EOF
cat > /k8s_yml/wordpress_demo/wordpress-svc.yml <<EOF
apiVersion: v1
kind: Service
metadata:
namespace: wordpress
name: wordpress
spec:
type: NodePort
ports:
- port: 80
nodePort: 30080
selector:
app: wordpress
EOF
wordpress-mysql基于rc书写
docker run --name mysql-wp -it \
-e MYSQL_DATABASE="blog" \
-e MYSQL_USER="blog" \
-e MYSQL_PASSWORD="blog" \
-e MYSQL_ROOT_PASSWORD="root_pwd" \
-d docker.io/mysql:5.7 \
--character-set-server=utf8 --collation-server=utf8_bin
docker run --name wordpress -p 81:80 --link mysql-wp:mysql -e WORDPRESS_DB_HOST=mysql \
-e WORDPRESS_DB_USER=blog
-e WORDPRESS_DB_NAME=blog
-e WORDPRESS_DB_PASSWORD=blog
-d docker.io/wordpress:latest
wget http://192.168.15.253/docker_images/wordpress-latest.tar.gz
docker load -i wordpress-latest.tar.gz
docker tag docker.io/wordpress:latest 10.0.0.11:5000/wordpress:latest
docker push 10.0.0.11:5000/wordpress:latest
法一:
rm -rf tomcat_demo
cp -a tomcat wordpress/
rename tomcat wordpress * #修改所有的tomcat为wordpress
cd wordpress
法二:
mkdir /k8s_yml/wordpress_demo && cd /k8s_yml/wordpress_demo
kubectl create namespace wordpress
kubectl create -f .
cat > /k8s_yml/wordpress_demo/mysql-rc.yml <<EOF
apiVersion: v1
kind: ReplicationController
metadata:
namespace: wordpress
name: mysql
spec:
replicas: 1
selector:
app: mysql
template:
metadata:
labels:
app: mysql
spec:
nodeName: 10.0.0.13
containers:
- name: mysql
image: 10.0.0.11:5000/mysql:5.7
ports:
- containerPort: 3306
env:
- name: MYSQL_ROOT_PASSWORD
value: 'root_pwd'
- name: MYSQL_DATABASE
value: 'blog'
- name: MYSQL_USER
value: 'blog'
- name: MYSQL_PASSWORD
value: 'blog'
args:
- --character-set-server=utf8
- --collation-server=utf8_bin
EOF
cat > /k8s_yml/wordpress_demo/mysql-svc.yml <<EOF
kind: Service
metadata:
namespace: wordpress
name: mysql
spec:
ports:
- port: 3306
targetPort: 3306
selector:
app: mysql
EOF
cat > /k8s_yml/wordpress_demo/wordpress-rc.yml <<EOF
apiVersion: v1
kind: ReplicationController
metadata:
namespace: wordpress
name: wordpress
spec:
replicas: 1
selector:
app: wordpress
template:
metadata:
labels:
app: wordpress
spec:
nodeName: 10.0.0.13
containers:
- name: wordpress
image: 10.0.0.11:5000/wordpress:latest
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
env:
- name: WORDPRESS_DB_HOST
value: 'mysql'
- name: WORDPRESS_DB_PASSWORD
value: 'blog'
- name: WORDPRESS_DB_USER
value: 'blog'
- name: WORDPRESS_DB_NAME
value: 'blog'
EOF
cat > /k8s_yml/wordpress_demo/wordpress-svc.yml <<EOF
apiVersion: v1
kind: Service
metadata:
namespace: wordpress
name: wordpress
spec:
type: NodePort
ports:
- port: 80
nodePort: 30006
selector:
app: wordpress
EOF
kubectl get all -n wordpress
wordpress-mysql基于deploy的书写
kubectl delete -f .
rename rc deploy *
tee /k8s_yml/wordpress_demo/mysql-deploy.yml<<-EOF
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
namespace: wordpress
name: mysql
spec:
replicas: 1
template:
metadata:
labels:
app: mysql
spec:
nodeName: 10.0.0.13
containers:
- name: mysql
image: 10.0.0.11:5000/mysql:5.7
ports:
- containerPort: 3306
env:
- name: MYSQL_ROOT_PASSWORD
value: 'root_pwd'
- name: MYSQL_DATABASE
value: 'blog'
- name: MYSQL_USER
value: 'blog'
- name: MYSQL_PASSWORD
value: 'blog'
args:
- --character-set-server=utf8
- --collation-server=utf8_bin
EOF
tee /k8s_yml/wordpress_demo/wordpress-deploy.yml <<-EOF
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
namespace: wordpress
name: wordpress
spec:
replicas: 1
template:
metadata:
labels:
app: wordpress
spec:
nodeName: 10.0.0.13
containers:
- name: wordpress
image: 10.0.0.11:5000/wordpress:latest
ports:
- containerPort: 80
env:
- name: WORDPRESS_DB_HOST
value: 'mysql'
- name: WORDPRESS_DB_PASSWORD
value: 'blog'
- name: WORDPRESS_DB_USER
value: 'blog'
- name: WORDPRESS_DB_NAME
value: 'blog'
EOF
kubectl create -f .
kubectl get all -n wordpress -o wide
注:快捷键操作
ndd
dw 快速切换到一整行的行尾 /HOME
行首 /END
健康检查和可用性检查
探针的种类
livenessProbe
:健康状态检查,周期性检查服务是否存活,检查结果失败,将重启容器
readinessProbe
:可用性检查,周期性检查服务是否可用,不可用将从service的endpoints中移除
探针的检测方法
- exec:执行一段命令 返回值为0正常, 非0不正常
- httpGet:检测某个 http 请求的返回状态码 2xx,3xx正常, 4xx,5xx错误
- tcpSocket:测试某个端口是否能够连接
liveness探针的exec使用
mkdir /k8s_yml/check/ -p && cd /k8s_yml/check
tee /k8s_yml/check/nginx_pod_exec.yaml <<-EOF
iapiVersion: v1
kind: Pod
metadata:
name: exec
spec:
containers:
- name: nginx
image: 10.0.0.11:5000/nginx:1.13
ports:
- containerPort: 80
args:
- /bin/sh
- -c
- touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 600
livenessProbe: # 模拟健康检查,启动后30s内健康,之后不健康
exec:
command:
- cat
- /tmp/healthy
initialDelaySeconds: 5 #初始化5秒后开始检查
periodSeconds: 5 #检查周期5秒一次
timeoutSeconds: 3 #检查命令超时时间,默认1s
successThreshold: 1 #检查成功1次就算成功,默认1次
failureThreshold: 1 # 检查失败1次就算失败,默认3次
EOF
kubectl create -f .
kubectl get pod -o yaml
name: exec
namespace: default 默认指定namespace空间
注:
args: - /bin/sh - -c - touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 600
等价
bin/sh -c "touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 600"
mysqladmin ping # 检测mysql存活
liveness探针的httpGet使用
mkdir /k8s_yml/check/ -p && cd /k8s_yml/check
tee nginx_pod_httpGet.yaml <<-EOF
iapiVersion: v1
kind: Pod
metadata:
name: httpget
spec:
containers:
- name: nginx
image: 10.0.0.11:5000/nginx:1.13
ports:
- containerPort: 80
livenessProbe:
httpGet:
path: /index.html
port: 80
initialDelaySeconds: 3
periodSeconds: 3
EOF
kubectl create -f nginx_pod_httpGet.yaml
kubectl describe pod httpget
kubectl exec -it httpget /bin/bash
rm -f /usr/share/nginx/html/index/html
exit
kubectl describe pod httpget
liveness探针的tcpSocket使用
mkdir /k8s_yml/check/ -p && cd /k8s_yml/check
tee /k8s_yml/check/nginx_pod_tcpSocket.yaml<<-EOF
iapiVersion: v1
kind: Pod
metadata:
name: tcpSocket
spec:
containers:
- name: nginx
image: 10.0.0.11:5000/nginx:1.13
ports:
- containerPort: 80
args:
- /bin/sh
- -c
- tail -f /etc/hosts
livenessProbe:
tcpSocket:
port: 80
initialDelaySeconds: 10
periodSeconds: 3
EOF
kubectl create -f nginx_pod_tcpSocket.yaml
kubectl describe pod tcpsocket
kubectl exec -it tcpsocket /bin/bash
nginx -s stop
exit
kubectl describe pod tcpsocket
exec: redis info 适合于不适合web界面的业务
httpget: web服务
readiness探针的httpGet使用
mkdir /k8s_yml/check/ -p && cd /k8s_yml/check
vi /k8s_yml/check/nginx-rc-httpGet.yaml
iapiVersion: v1
kind: ReplicationController
metadata:
name: readiness
spec:
replicas: 2
selector:
app: readiness
template:
metadata:
labels:
app: readiness
spec:
containers:
- name: readiness
image: 10.0.0.11:5000/nginx:1.13
ports:
- containerPort: 80
readinessProbe:
httpGet:
path: /qiangge.html
port: 80
initialDelaySeconds: 3
periodSeconds: 3
readiness
web服务
httpget
kubectl create -f nginx-rc-httpGet.yaml
kubectl get rc
kubectl get pod
kubectl expose rc readiness --type=NodePort --port=80 --target-port=80
#加入server服务
echo 'web01' > /usr/share/nginx/html/qiangge.html
exit
kubectl get pod
kubectl describe svc readiness
部署Dashboard服务
- node2节点(10.0.0.13)下载镜像,并导入,打标(来自tenxcloud仓库)
[root@k8s-node-2 opt]# docker load -i kubernetes-dashboard-amd64_v1.4.1.tar.gz
5f70bf18a086: Loading layer 1.024 kB/1.024 kB
2e350fa8cbdf: Loading layer 86.96 MB/86.96 MB
Loaded image: index.tenxcloud.com/google_containers/kubernetes-dashboard-amd64:v1.4.1
[root@k8s-node-2 opt]# docker tag index.tenxcloud.com/google_containers/kubernetes-dashboard-amd64:v1.4.1 10.0.0.11:5000/kubernetes-dashboard-amd64:v1.4.1
- master节点创建配置文件(指定调度到node2)
mkdir -p /root/k8s_yaml/dashboard/ && cd /root/k8s_yaml/dashboard/
cat > /root/k8s_yaml/dashboard/dashboard.yaml <<EOF
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
# Keep the name in sync with image version and
# gce/coreos/kube-manifests/addons/dashboard counterparts
name: kubernetes-dashboard-latest
namespace: kube-system
spec:
replicas: 1
template:
metadata:
labels:
k8s-app: kubernetes-dashboard
version: latest
kubernetes.io/cluster-service: "true"
spec:
nodeName: 10.0.0.13 # 指定调度到的node
containers:
- name: kubernetes-dashboard
image: 10.0.0.11:5000/kubernetes-dashboard-amd64:v1.4.1
resources:
# keep request = limit to keep this container in guaranteed class
limits:
cpu: 100m
memory: 50Mi
requests:
cpu: 100m
memory: 50Mi
ports:
- containerPort: 9090
args:
- --apiserver-host=http://10.0.0.11:8080
livenessProbe:
httpGet:
path: /
port: 9090
initialDelaySeconds: 30
timeoutSeconds: 30
EOF
cat > /root/k8s_yaml/dashboard/dashboard-svc.yaml <<EOF
apiVersion: v1
kind: Service
metadata:
name: kubernetes-dashboard
namespace: kube-system
labels:
k8s-app: kubernetes-dashboard
kubernetes.io/cluster-service: "true"
spec:
selector:
k8s-app: kubernetes-dashboard
ports:
- port: 80
targetPort: 9090
EOF
- master节点创建dashboard的资源
kubectl create -f .
- master节点检查命名空间kube-system
kubectl get all -n kube-system
全局资源
- Namespaces
- Nodes
- Persistemt Volume Claims
局部资源(各Namespaces分别使用的资源)
daemonsets
daemonset的应用场景: 刚好一个node节点只需要跑一个服务的应用
daemonset: 不需要指定副本数,不需要scheduler调度
监控 node-exporter 3个计算节点 deployment scale调度
mkdir /k8s_yml/daemonset && cd /k8s_yml/daemonset
tee k8s_daemon.yml <<-EOF
apiVersion: extensions/v1beta1
kind: DaemonSet
metadata:
name: nginx
spec:
template:
metadata:
labels:
app: oldboy #更改标签
spec:
containers:
- name: nginx
image: 10.0.0.11:5000/nginx:1.13
ports:
- containerPort: 80
EOF
kubectl create -f k8s_daemon.yml
kubectl get pod -o wide
kubectl get pod
注:标签不要相同
pet sets:宠物应用 有状态的应用 pod名字固定 01 02 03
其他: 畜生应用 无状态的应用 pod名字随机
statsfulset:数据库的应用 redis esj集群 mysql
jobs: 一次性任务 complete
pod: 一直运行
cronjobs: 定时任务
service: 四层负载均衡
ingresses: 七层负载均衡
pvc和pv 存储
config 配置
secret: 密码,秘钥
config maps:配置文件
通过api-server反向代理访问service
-
分析dashboard服务web页面
主页+锚点(#)
http://10.0.0.11:8080/api/v1/proxy/namespaces/kube-system/services/kubernetes-dashboard/#/workload?namespace=default
- 查看所有命名空间的svc
kubectl get svc --all-namespaces
- 通过apiservice反向代理访问service资源
http://10.0.0.11:8080/api/v1/proxy/namespaces/命名空间名称/services/service名称/
弹性伸缩
Kubernetes HPA(Horizontal Pod Autoscaler)Pod 水平自动扩缩:可以基于 CPU 利用率自动扩缩 ReplicationController、Deployment、ReplicaSet 和 StatefulSet 中的 Pod 数量。 除了 CPU 利用率,也可以基于其他应程序提供的自定义度量指标来执行自动扩缩。 但不适用于无法扩缩的对象,比如 DaemonSet。
Pod 水平自动扩缩特性由 Kubernetes API 资源和控制器实现。资源决定了控制器的行为。 控制器会周期性的调整副本控制器或 Deployment 中的副本数量,以使得 Pod 的平均 CPU 利用率与用户所设定的目标值匹配。
Pod水平自动伸缩:
- 1.11版本之前,依赖heapster监控各node节点信息。
- 1.11版本之后,使用Horizontal Pod Autoscaling资源
HPA工作机制
安装heapster监控
k8s原生集群监控方案(Heapster+InfluxDB+Grafana+Dashboard) :
Heapster处理数据储存到InfluxDB,Grafana从InfluxDB读取数据出图,Dashboard调用Grafana的图。
1.node2节点(10.0.0.13)下载镜像,并导入,打标**(3个镜像,来自官方仓库)
ls *.tar.gz
for n in `ls *.tar.gz`;do docker load -i $n ;done
docker tag docker.io/kubernetes/heapster_grafana:v2.6.0 10.0.0.11:5000/heapster_grafana:v2.6.0
docker tag docker.io/kubernetes/heapster_influxdb:v0.5 10.0.0.11:5000/heapster_influxdb:v0.5
docker tag docker.io/kubernetes/heapster:canary 10.0.0.11:5000/heapster:canary
2.master节点创建配置文件(指定调度到node2)
mkdir /k8s_yml/heapster && cd /k8s_yml/heapster
rz heapster-influxdb.zip
mv heapster-influxdb/* .
rm -rf heapster-influxdb
tee /k8s_yml/heapster/heapster-controller.yaml <<-EOF
apiVersion: v1
kind: ReplicationController
metadata:
labels:
k8s-app: heapster
name: heapster
version: v6
name: heapster
namespace: kube-system
spec:
replicas: 1
selector:
k8s-app: heapster
version: v6
template:
metadata:
labels:
k8s-app: heapster
version: v6
spec:
nodeName: 10.0.0.13 # 指定调度到的node
containers:
- name: heapster
image: 10.0.0.11:5000/heapster:canary
#imagePullPolicy: Always
command:
- /heapster
- --source=kubernetes:http://10.0.0.11:8080?inClusterConfig=false
- --sink=influxdb:http://monitoring-influxdb:8086
EOF
tee /k8s_yml/heapster/influxdb-grafana-controller.yaml <<-EOF
apiVersion: v1
kind: ReplicationController
metadata:
labels:
name: influxGrafana
name: influxdb-grafana
namespace: kube-system
spec:
replicas: 1
selector:
name: influxGrafana
template:
metadata:
labels:
name: influxGrafana
spec:
nodeName: 10.0.0.13
containers:
- name: influxdb
image: 10.0.0.11:5000/heapster_influxdb:v0.5
volumeMounts:
- mountPath: /data
name: influxdb-storage
- name: grafana
image: 10.0.0.11:5000/heapster_grafana:v2.6.0
env:
- name: INFLUXDB_SERVICE_URL
value: http://monitoring-influxdb:8086
# The following env variables are required to make Grafana accessible via
# the kubernetes api-server proxy. On production clusters, we recommend
# removing these env variables, setup auth for grafana, and expose the grafana
# service using a LoadBalancer or a public IP.
- name: GF_AUTH_BASIC_ENABLED
value: "false"
- name: GF_AUTH_ANONYMOUS_ENABLED
value: "true"
- name: GF_AUTH_ANONYMOUS_ORG_ROLE
value: Admin
- name: GF_SERVER_ROOT_URL
value: /api/v1/proxy/namespaces/kube-system/services/monitoring-grafana/
volumeMounts:
- mountPath: /var
name: grafana-storage
volumes:
- name: influxdb-storage
emptyDir: {}
- name: grafana-storage
emptyDir: {}
EOF
- master节点创建dashboard的资源
kubectl create -f .
- master节点检查命名空间kube-system,查看集群信息
kubectl get all -n kube-system
kubectl cluster-info
- 浏览器访问dashboard验证:http://10.0.0.11:8080/ui/
- 可以使用top命令
kubectl top node
弹性伸缩
HPA YAML默认文件
apiVersion: autoscaling/v1
kind: HorizontalPodAutoscaler
metadata:
creationTimestamp: 2017-06-29T08:04:08Z
name: nginxtest
namespace: default
resourceVersion: "951016361"
selfLink: /apis/autoscaling/v1/namespaces/default/horizontalpodautoscalers/nginxtest
uid: 86febb63-5ca1-11e7-aaef-5254004e79a3
spec:
maxReplicas: 5 //资源最大副本数
minReplicas: 1 //资源最小副本数
scaleTargetRef:
apiVersion: extensions/v1beta1
kind: Deployment //需要伸缩的资源类型
name: nginxtest //需要伸缩的资源名称
targetCPUUtilizationPercentage: 50 //触发伸缩的cpu使用率
status:
currentCPUUtilizationPercentage: 48 //当前资源下pod的cpu使用率
currentReplicas: 1 //当前的副本数
desiredReplicas: 2 //期望的副本数
lastScaleTime: 2017-07-03T06:32:19Z
1.master节点创建测试Deployment和svc资源
cd /root/k8s_yaml/deploy
cat > /root/k8s_yaml/deploy/k8s_deploy2.yaml <<EOF
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: nginx
spec:
replicas: 3
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: 10.0.0.11:5000/nginx:1.13
ports:
- containerPort: 80
resources:
limits:
cpu: 100m
memory: 50Mi
requests:
cpu: 100m
memory: 50Mi
EOF
kubectl create -f k8s_deploy2.yaml
kubectl expose deploy nginx --type=NodePort --port=80 --target-port=80
- 创建弹性伸缩规则
kubectl autoscale deploy nginx --max=8 --min=1 --cpu-percent=5
- 查看hpa资源,nginx访问地址IP:PORT
kubectl get all -o wide
- 查看hpa资源配置文件
kubectl get hpa nginx -o yaml
- 压测
yum install httpd-tools -y
ab -n 1000000 -c 40 http://10.0.0.12:32114/index.html
压测前:
压测10s后,自动扩容:
停止压测5分钟后,自动缩容:
emptyDir+tomcat
kubectl get pod -n tomcat -o wide
kubectl exec -n tomcat -it mysql-8ltcq /bin/bash
mysql -uroot -p123456
kubectl explain pod.spec.containers
kubectl explain pod.spec.containers.volumeMounts
kubectl explain pod.spec.volumes #查看volumes帮助
a.master节点创建emptyDir持久化配置文件
tee /k8s_yml/tomcat_demo/mysql-emptyDir.yml <<-EOF
apiVersion: v1
kind: ReplicationController
metadata:
name: mysql
spec:
replicas: 1
selector:
app: mysql
template:
metadata:
labels:
app: mysql
spec:
nodeName: 10.0.0.12
volumes:
- name: mysql
emptyDir: {}
containers:
- name: wp-mysql
image: 10.0.0.11:5000/mysql:5.7
imagePullPolicy: IfNotPresent
ports:
- containerPort: 3306
volumeMounts:
- mountPath: /var/lib/mysql
name: mysql
env:
- name: MYSQL_ROOT_PASSWORD
value: '123456'
EOF
b.master节点删除原rc资源,创建emptyDir持久化的rc资源
kubectl delete -f mysql-rc.yml
kubectl create -f mysql-emptyDir.yml
c.node节点查看临时目录
ll /var/lib/kubelet/pods/
ll /var/lib/kubelet/pods/sha256号/volumes/kubernetes.io~empty-dir/mysql
持久化存储
为了保证数据不丢失
查看持久化计划信息
kubectl explain pod.spec.containers.volumeMounts
kubectl explain pod.spec.volumes
持久化存储类型:
- emptyDir:共享pod生存期的临时目录。
- hostPath:主机上预先存在的文件或目录直接公开给容器。这通常用于允许查看主机的系统代理或其他特权对象。
- nfs:共享pod生存期的NFS装载。
emptyDir
临时的空目录:伴随pod的生命周期,随着pod删除而删除,数据持久化但不共享。
适用于存放日志(pod之间不同,但需要保存的数据)。
emptyDir是一种临时存储,pod创建的时候会在node节点上为容器申请一个临时的目录,跟随容器的生命周期,若容器删除,emptyDir定义的临时存储空间也会随之删除,容器发生意外crash则不受影响,同时如果容器发生了迁移,其上的数据也会丢失,emptyDir一般用于测试,或者缓存场景。注意:容器崩溃不会导致数据的丢失,因为容器的崩溃并不移除pod.
emptyDir
的一些用途:
- 缓存空间,例如基于磁盘的归并排序。
- 为耗时较长的计算任务提供检查点,以便任务能方便地从崩溃前状态恢复执行。
- 在 Web 服务器容器服务数据时,保存内容管理器容器获取的文件。
- 创建tomcat+mysql的资源
cd /root/k8s_yaml/tomcat_demo && kubectl create -f .
- 访问:http://10.0.0.12:30008/demo/,添加数据
- node节点清空容器,虽然会重启一批容器,但之前添加的数据没了,因此需要持久化存储
docker rm -f `docker ps -aq`
- master节点创建emptyDir持久化配置文件
cat > /k8s_yml/tomcat_demo/mysql-emptyDir.yml <<EOF
apiVersion: v1
kind: ReplicationController
metadata:
name: mysql
spec:
replicas: 1
selector:
app: mysql
template:
metadata:
labels:
app: mysql
spec:
nodeName: 10.0.0.12
volumes:
- name: mysql
emptyDir: {}
containers:
- name: wp-mysql
image: 10.0.0.11:5000/mysql:5.7
imagePullPolicy: IfNotPresent
ports:
- containerPort: 3306
volumeMounts:
- mountPath: /var/lib/mysql
name: mysql
env:
- name: MYSQL_ROOT_PASSWORD
value: '123456'
EOF
- master节点删除原rc资源,创建emptyDir持久化的rc资源
kubectl delete -f mysql-rc.yml
kubectl create -f mysql-emptyDir.yml
- node节点查看临时目录
ll /var/lib/kubelet/pods/
ll /var/lib/kubelet/pods/sha256号/volumes/kubernetes.io~empty-dir/mysql
删除pod,这个文件也会自动删除。
HostPath
HostPath:可以多个容器共享持久化数据,但不能跨宿主机。
表示主机上预先存在的文件或目录直接暴露在容器中。
可以实现数据共享存储;
hostPath
卷能将node宿主机节点文件系统上的文件或目录挂载到您的 Pod 中。
- 运行一个需要访问 Docker 引擎内部机制的容器;请使用
hostPath
挂载/var/lib/docker
路径。 - 在容器中运行 cAdvisor 时,以
hostPath
方式挂载/sys
。 - 允许 Pod 指定给定的
hostPath
在运行 Pod 之前是否应该存在,是否应该创建以及应该以什么方式存在。
使用这种类型的卷时要小心,因为:
- 具有相同配置(例如从 podTemplate 创建)的多个 Pod 会由于节点上文件的不同而在不同节点上有不同的行为。
- 当 Kubernetes 按照计划添加资源感知的调度时,这类调度机制将无法考虑由
hostPath
使用的资源。 - 基础主机上创建的文件或目录只能由 root 用户写入。您需要在特权容器中以 root 身份运行进程,或者修改主机上的文件权限以便容器能够写入
hostPath
卷。
- master节点创建wordpress+mysql资源
cd /k8s_yml/wordpress_demo
kubectl create namespace wordpress
kubectl create -f .
- master节点持久化mysql
cat > /k8s_yml/wordpress_demo/mysql-demo.yml <<EOF
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
namespace: wordpress
name: mysql
spec:
replicas: 1
template:
metadata:
labels:
app: mysql
spec:
nodeName: 10.0.0.12
volumes:
- name: mysql
emptyDir: {}
containers:
- name: mysql
image: 10.0.0.11:5000/mysql:5.7
volumeMounts:
- mountPath: /var/lib/mysql
name: mysql
ports:
- containerPort: 3306
env:
- name: MYSQL_ROOT_PASSWORD
value: 'root_pwd'
- name: MYSQL_DATABASE
value: 'blog'
- name: MYSQL_USER
value: 'blog'
- name: MYSQL_PASSWORD
value: 'blog'
args:
- --character-set-server=utf8
- --collation-server=utf8_bin
EOF
- master节点应用配置文件:新建一个资源,此次不适用
kubectl apply -f mysql-demo.yml
kubectl get pod -o wide -n wordpress
kubectl delete deploy -n wordpress --all
kubectl create -f mysql-demo.yml
kubectl create -f wordpress-demo.yml
- master节点持久化wordpress
cat > /k8s_yml/wordpress_demo/wordpress-demo.yml <<EOF
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
namespace: wordpress
name: wordpress
spec:
replicas: 1
template:
metadata:
labels:
app: wordpress
spec:
nodeName: 10.0.0.12
volumes:
- name: wp-code
hostPath:
path: /data/wp-code
containers:
- name: wordpress
image: 10.0.0.11:5000/wordpress:latest
imagePullPolicy: IfNotPresent
volumeMounts:
- name: wp-code
mountPath: /var/www/html
ports:
- containerPort: 80
env:
- name: WORDPRESS_DB_HOST
value: 'mysql'
- name: WORDPRESS_DB_PASSWORD
value: 'blog'
- name: WORDPRESS_DB_USER
value: 'blog'
- name: WORDPRESS_DB_NAME
value: 'blog'
EOF
- master节点替换配置文件,删除所有pod生效
mkdir -p /data/wp-code
kubectl replace -f wordpress-demo.yml
kubectl delete pod -n wordpress --all
kubectl get pod -o wide -n wordpress
-
安装wordpress:http://10.0.0.13:30006/
-
node2(10.0.0.13)节点查看持久化目录
ll /data/wp-code
-
wordpress上传图片
-
node2查看上传图片
ll /data/wp-code/wp-content/uploads/
删除pod时,文件不会删除掉,还要保存到node上。
- master节点修改副本数
kubectl scale -n wordpress deployment wordpress --replicas=2
- master节点查看pod资源
kubectl get pod -o wide -n wordpress
- node2创建phpinfo页面
echo "<?php phpinfo() ?>" > /data/wp-code/info.php
- 访问phpinfo页面,验证调度到多个pod,但共享数据
curl 10.0.0.12:30006/info.php | grep -i 172.18.98
NFS
NFS:可以多个容器跨宿主机共享持久化数据。
- 所有节点安装nfs-utils
yum -y install nfs-utils
- master节点部署nfs服务
mkdir -p /data/tomcat-db
cat > /etc/exports <<EOF
/data 10.0.0.0/24(rw,sync,no_root_squash,no_all_squash)
EOF
systemctl restart rpcbind
systemctl restart nfs
- 所有node节点检查挂载
showmount -e 10.0.0.11
- master节点创建nfs持久化配置文件
cd /root/k8s_yaml/tomcat_demo
cat > /k8s_yml/tomcat_demo/mysql-emptyDir.yml <<EOF
apiVersion: v1
kind: ReplicationController
metadata:
name: mysql
spec:
replicas: 1
selector:
app: mysql
template:
metadata:
labels:
app: mysql
spec:
volumes:
- name: mysql
nfs:
path: /data/tomcat-db
server: 10.0.0.11
containers:
- name: wp-mysql
image: 10.0.0.11:5000/mysql:5.7
imagePullPolicy: IfNotPresent
ports:
- containerPort: 3306
volumeMounts:
- mountPath: /var/lib/mysql
name: mysql
env:
- name: MYSQL_ROOT_PASSWORD
value: '123456'
EOF
- master节点替换配置文件,删除所有pod生效
kubectl create -f mysql-emptyDir.yml
kubectl replace -f mysql-emptyDir.yml
kubectl delete pod --all
kubectl get pod -o wide
- node1查看nfs挂载
df -Th|grep nfs
-
master节点修改配置文件:调度到13上
cat > /k8s_yml/tomcat_demo/mysql-emptyDir.yml <<EOF
apiVersion: v1
kind: ReplicationController
metadata:
name: mysql
spec:
replicas: 1
selector:
app: mysql
template:
metadata:
labels:
app: mysql
spec:
nodeName: 10.0.0.13
volumes:
- name: mysql
nfs:
path: /data/tomcat-db
server: 10.0.0.11
containers:
- name: wp-mysql
image: 10.0.0.11:5000/mysql:5.7
imagePullPolicy: IfNotPresent
ports:
- containerPort: 3306
volumeMounts:
- mountPath: /var/lib/mysql
name: mysql
env:
- name: MYSQL_ROOT_PASSWORD
value: '123456'
EOF
- master节点替换配置文件,删除所有pod生效
kubectl replace -f mysql-emptyDir.yml
kubectl delete pod --all
kubectl get pod -o wide
- node2查看nfs挂载
df -Th|grep nfs
PV和PVC
PersistentVolume(持久化卷):全局资源,是对底层的共享存储的一种抽象。PV 由管理员进行创建和配置,它和具体的底层的共享存储技术的实现方式有关,比如 Ceph、GlusterFS、NFS 等,都是通过插件机制完成与共享存储的对接。
PersistentVolumeClaim(持久化卷声明):局部资源,属于某一个namespace。PVC 是用户存储的一种声明,PVC 和 Pod 比较类似,Pod 消耗的是节点,PVC 消耗的是 PV 资源,Pod 可以请求 CPU 和内存,而 PVC 可以请求特定的存储空间和访问模式。对于真正使用存储的用户不需要关心底层的存储实现细节,只需要直接使用 PVC 即可。
- Volumes:最基础的存储抽象,其支持多种类型,包括本地存储、NFS、FC以及众多的云存储,我们也可以编写自己的存储插件来支持特定的存储系统。Volume可以被Pod直接使用,也可以被PV使用。普通的Volume和Pod之间是一种静态的绑定关系,在定义Pod的同时,通过volume属性来定义存储的类型,通过volumeMount来定义容器内的挂载点。
- PersistentVolume:是Kubernetes中的一个资源对象,创建一个PV相当于创建了一个存储资源对象,这个资源的使用要通过PVC来请求。
- PersistentVolumeClaim:是用户对存储资源PV的请求,根据PVC中指定的条件Kubernetes动态的寻找系统中的PV资源并进行绑定。目前PVC与PV匹配可以通过StorageClassName、matchLabels或者matchExpressions三种方式。
- StorageClass:存储类,目前kubernetes支持很多存储,例如ceph,nfs。glusterfs等。
生命周期
PV是集群中的资源。PVC是对这些资源的请求,也是对资源的索赔检查。 PV和PVC之间的相互作用遵循这个生命周期:Provisioning ——-> Binding ——–>Using——>Releasing——>Recycling
PVC 处理流程
Provisioning
PV的提供方式:静态或者动态。
- Static:集群管理员创建多个PV。 它们携带可供集群用户使用的真实存储的详细信息。 它们存在于Kubernetes API中,可用于消费。
- Dynamic:当管理员创建的静态PV都不匹配用户的PersistentVolumeClaim时,集群可能会尝试为PVC动态配置卷。 此配置基于StorageClasses:PVC必须请求一个类,并且管理员必须已创建并配置该类才能进行动态配置。 要求该类的声明有效地为自己禁用动态配置。
PV访问模式
- RWO - ReadWriteOnce——该卷可以被单个节点以读/写模式挂载
- ROX - ReadOnlyMany——该卷可以被多个节点以只读模式挂载
- RWX - ReadWriteMany——该卷可以被多个节点以读/写模式挂载
- master节点创建svc配置文件
mkdir -p /k8s_yml/volume && cd /k8s_yml/volume
cat > /k8s_yml/volume/mysql-svc.yml <<EOF
apiVersion: v1
kind: Service
metadata:
namespace: tomcat
name: mysql
spec:
ports:
- port: 3306
targetPort: 3306
selector:
app: mysql
EOF
cat > /k8s_yml/volume/tomcat-svc.yml <<EOF
apiVersion: v1
kind: Service
metadata:
namespace: tomcat
name: myweb
spec:
type: NodePort
ports:
- port: 8080
nodePort: 30008
selector:
app: myweb
EOF
- master节点创建pv配置文件
mkdir -p /data/pv{1,2,3}
cat > /k8s_yml/volume/pv1.yaml <<EOF
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv1
labels:
type: nfs001
spec:
capacity:
storage: 10Gi # 不会去验证是否真的有这么多空间
accessModes:
- ReadWriteMany # 允许多个pod读写,实现共享
persistentVolumeReclaimPolicy: Recycle # 回收策略:回收
nfs:
path: "/data/pv1"
server: 10.0.0.11
readOnly: false
EOF
cat > /k8s_yml/volume/pv2.yaml <<EOF
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv2
labels:
type: nfs001
spec:
capacity:
storage: 20Gi
accessModes:
- ReadWriteMany
persistentVolumeReclaimPolicy: Recycle
nfs:
path: "/data/pv2"
server: 10.0.0.11
readOnly: false
EOF
cat > /k8s_yml/volume/pv3.yaml <<EOF
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv3
labels:
type: ssd
spec:
capacity:
storage: 50Gi
accessModes:
- ReadWriteMany
persistentVolumeReclaimPolicy: Recycle
nfs:
path: "/data/pv3"
server: 10.0.0.11
readOnly: false
EOF
回收策略:
kubectl explain persistentvolumes.spec.persistentVolumeReclaimPolicy
Retain(保留):手动回收pv。默认
Recycle(回收):基本擦除pv( rm -rf /thevolume/* )
Delete(删除):关联的存储资产(例如 AWS EBS、GCE PD、Azure Disk 和 OpenStack Cinder 卷) 将被删除
当前,只有 NFS 和 HostPath 支持回收策略。AWS EBS、GCE PD、Azure Disk 和 Cinder 卷支持删除策略
- master节点创建pv资源
kubectl create namespace tomcat
kubectl create -f .
- master节点查看pv资源
kubectl get pv
pv卷状态:
- Available(可用):一块空闲资源还没有被任何声明绑定
- Bound(已绑定):卷已经被声明绑定
- Released(已释放):声明被删除,但是资源还未被集群重新声明
- Failed(失败):该卷的自动回收失败 命令行会显示绑定到 PV 的 PVC 的名称
- master节点创建pvc配置文件
cat > /k8s_yml/volume/mysql_pvc.yaml <<EOF
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
namespace: tomcat
name: tomcat-mysql
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 30Gi
EOF
- master节点创建pvc资源
kubectl create -f mysql_pvc.yaml
- master节点查看pv和pvc资源
kubectl get pv
kubectl get pvc -n tomcat
- master节点创建Deployment资源:pod模板里使用volume
cat > /k8s_yml/volume/mysql-rc.yml <<EOF
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
namespace: tomcat
name: mysql
spec:
replicas: 1
selector:
app: mysql
template:
metadata:
labels:
app: mysql
spec:
nodeName: 10.0.0.12
volumes:
- name: mysql
persistentVolumeClaim:
claimName: tomcat-mysql
containers:
- name: wp-mysql
image: 10.0.0.11:5000/mysql:5.7
imagePullPolicy: IfNotPresent
ports:
- containerPort: 3306
volumeMounts:
- mountPath: /var/lib/mysql
name: mysql
env:
- name: MYSQL_ROOT_PASSWORD
value: '123456'
EOF
- master节点创建pvc资源
kubectl create -f mysql-rc.yml
- master节点验证pv和pvc资源的使用
kubectl get pv
kubectl get pod -n tomcat
kubectl describe pod -n tomcat mysql-k90jm | grep -i persistentVolumeClaim
kubectl describe pod -n tomcat mysql-k90jm | grep -i tomcat-mysql
回收pv资源
- master节点删除tomcat命名空间
kubectl delete namespace tomcat
- master节点查看pv处于回收状态,会创建一个pod用来回收(镜像在Google仓库)
kubectl get pv
kubectl get pod
- master节点修改镜像地址为阿里云源
kubectl edit pod recycler-for-pv3
image: registry.aliyuncs.com/google_containers/busybox:latest
- master节点查看pod正常运行
kubectl get pod
- master节点查看pv回收完毕,处于正常状态
kubectl get pv
kubectl get pv --show-labels
标签选择器(优先)
- master节点创建pv配置文件
mkdir /data/pv4 -p
cat > /k8s_yml/volume/pv4.yaml <<EOF
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv4
labels:
type: sata
spec:
capacity:
storage: 50Gi
accessModes:
- ReadWriteMany
persistentVolumeReclaimPolicy: Recycle #回收策略
nfs:
path: "/data/pv4"
server: 10.0.0.11
readOnly: false
EOF
- master节点创建pv资源
kubectl create -f pv4.yaml
- master节点查看pv资源的标签
kubectl get pv --show-labels
- master节点创建pvc配置文件:使用标签选择器
cat > /k8s_yml/volume/mysql_pvc2.yaml <<EOF
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: tomcat-mysql
spec:
selector:
matchLabels:
type: ssd
accessModes:
- ReadWriteMany
resources:
requests:
storage: 10Gi
EOF
- master节点创建pvc资源
kubectl create -f mysql_pvc2.yaml
- master节点验证pv资源优先使用标签选择器的指定
kubectl get pv --show-labels
注:delete也可以,需要安装一定的插件
Ceph
Storage:
-
存储硬件:nas,san
-
存储软件:nfs,lvm
Storage方式
- 块存储:提供硬盘,lvm,cinder
- 文件存储:提供目录,nfs(单机存储),glusterfs(分布式存储)
- 对象存储:提供接口,fastdfs,Swift,ceph(分布式存储)
存储方式 | 技术实现 | 优势 | 劣势 | 代表作 |
---|---|---|---|---|
块存储 | 裸盘上划分逻辑卷,逻辑卷格式化成任意文件系统 | 支持多种文件系统,传输速度快,提供硬件容错机制 | 无法实现网络共享 | FC-SAN,iSCSI |
文件存储 | 在格式化的磁盘上存储文件 | 提供网络共享 | 网络传输速度制约读写速度,分层目录结构限制可扩展性 | NFS,FAT,EXT3 |
对象存储 | 以灵活可定制的对象为存储单元,元数据服务器提供快速并发寻址 | 读写速度较快的同时支持网络共享,对象灵活定义 | 管理软件的购买、使用和运维成本高 | Swift |
块存储
典型设备: 磁盘阵列,硬盘
块存储主要是将裸磁盘空间整个映射给主机使用的。
通过划逻辑盘、做Raid、或者LVM(逻辑卷)等种种方式逻辑划分出N个逻辑的硬盘。
接着块存储会采用映射的方式将这几个逻辑盘映射给主机,操作系统还需要对挂载的裸硬盘进行分区、格式化后,才能使用,与平常主机内置硬盘的方式完全无异。
优点:
-
通过了Raid与LVM等手段,对数据提供了保护。
-
将多块廉价的硬盘组合起来,成为一个大容量的逻辑盘对外提供服务,提高了容量。
-
可以并行写入,提升读写效率。
-
很多时候块存储采用SAN架构组网,传输速率以及封装协议的原因,使得传输速度与读写速率得到提升。
缺点:
-
采用SAN架构组网时,需要额外为主机购买光纤通道卡,还要买光纤交换机,成本高。
-
主机之间的数据无法共享。不利于不同操作系统主机间的数据共享。
文件存储
典型设备:FTP、NFS服务器
为了克服块存储中文件服务共享的问题,所以有了文件存储。
主机A可以直接对文件存储进行文件的上传下载,与块存储不同,主机A是不需要再对文件存储进行格式化的,因为文件管理功能已经由文件存储自己搞定了。
优点:
-
造价低:随便一台机器,普通以太网就可以,不需要SAN网络。
-
方便文件共享:针对块存储中文件无法共享问题,使用文件存储,第三方进行中转。
缺点:
- 读写速率低,传输速率慢:以太网,上传下载速度较慢;另外所有读写都要1台服务器里面的硬盘来承担,相比起磁盘阵列动不动就几十上百块硬盘同时读写,速率慢了许多。
对象存储
典型设备:内置大容量硬盘的分布式服务器
对象存储最常用的方案,就是多台服务器内置大容量硬盘,再装上对象存储软件,然后搞几台服务器作为管理节点,安装上对象存储管理软件。管理节点可以管理其他服务器对外提供读写访问功能。
块存储读写快,不利于共享,文件存储读写慢,利于共享。能否搞一个读写快,利于共享的出来呢?于是有了对象存储。对象存储结合了块存储与文件存储的优点。
对象存储中,OSD(Object-based Storage Device)是对象存储设备,MDS(Metadata Server)是元数据服务器。
对象存储的原理
首先,一个文件包含了属性(术语叫metadata,元数据,例如该文件的大小、修改时间、存储路径等)以及内容(以下简称数据)。
以往像FAT32这种文件系统,是直接将一份文件的数据与metadata一起存储的,存储过程先将文件按照文件系统的最小块大小来打散(如4M的文件,假设文件系统要求一个块4K,那么就将文件打散成1000个小块),再写进硬盘里面,过程中没有区分数据/metadata的。而每个块最后会告知你下一个要读取的块的地址,然后一直这样顺序地按图索骥,最后完成整份文件的所有块的读取。
对象存储将元数据独立出来,控制节点叫元数据服务器(服务器+对象存储管理软件),里面主要负责存储对象的属性(主要是对象的数据被打散存放到了那几台分布式服务器中的信息),而其他负责存储数据的分布式服务器叫做OSD,主要负责存储文件的数据部分。当用户访问对象,会先访问元数据服务器,元数据服务器只负责反馈对象存储在那些OSD,假设反馈文件A存储在B、C、D三台OSD,那么用户就会再次直接访问3台OSD服务器去读取数据。
这时候由于是3台OSD同时对外传输数据,所以传输的速度就加快了。当OSD服务器数量越多,这种读写速度的提升就越大,通过这种方式,实现了读写快的目的。
另一方面,对象存储软件是有专门的文件系统的,所以OSD对象又相当于文件服务器,那么就不存在文件共享方面的困难了,也就解决了文件共享方面的问题。
总结
-
块存储可以认为是裸盘,最多包一层逻辑卷(LVM);常见的DAS、FC-SAN、IP-SAN都是块存储,块存储最明显的特征就是不能被操作系统直接读写,需要格式化为指定的文件系统(Ext3、Ext4、NTFS)后才可以访问。优点:读写快(带宽&IOPS);缺点:因为太底层了,不利于扩展。
-
文件存储:指的是在文件系统上的存储,也就是主机操作系统中的文件系统。
-
对象存储,对象存储肯定是分布式存储,但分布式存储可能是分布式文件系统,不一定是对象存储;常见的对象存储开源实现有 Ceph 的RADOS、openstack的swift、AWS s3等,常见分布式文件系统,lustre、glusterfs、HDFS等;对象存储和分布式文件系统的表面区别:对象存储支持的访问接口基本都是restful接口、而分布式文件系统提供的POSIX兼容的文件操作接口;
分布式文件系统和对象存储最本质的区别:
分布式文件系统文件组织方式为目录树、对象存储采用的则是扁平的组织方式;对象存储不支持随机读取和写入,put和get操作都是针对的整个文件。
Ceph 简介
Ceph 独一无二地在一个统一的系统中同时提供了对象、块、和文件存储功能。
它可靠性高、管理简单,并且是开源软件。 Ceph 的强大可以改变您公司的 IT 基础架构和海量数据管理能力。
Ceph 可提供极大的伸缩性——供成千用户访问 PB 乃至 EB 级的数据。 Ceph 节点以普通硬件和智能守护进程作为支撑点, Ceph 存储集群组织起了大量节点,它们之间靠相互通讯来复制数据、并动态地重分布数据。
CEPH 对象存储
- REST 风格的接口
- 与 S3 和 Swift 兼容的 API
- S3 风格的子域
- 统一的 S3/Swift 命名空间
- 用户管理
- 利用率跟踪
- 条带化对象
- 云解决方案集成
- 多站点部署
- 灾难恢复
CEPH 块设备
- 瘦接口支持
- 映像尺寸最大 16EB
- 条带化可定制
- 内存缓存
- 快照
- 写时复制克隆
- 支持内核级驱动
- 支持 KVM 和 libvirt
- 可作为云解决方案的后端
- 增量备份
CEPH 文件系统
- 与 POSIX 兼容的语义
- 元数据独立于数据
- 动态重均衡
- 子目录快照
- 可配置的条带化
- 有内核驱动支持
- 有用户空间驱动支持
- 可作为 NFS/CIFS 部署
- 可用于 Hadoop (取代 HDFS)
Ceph 特点
高性能
- 摒弃了传统的集中式存储元数据寻址的方案,采用CRUSH算法,数据分布均衡,并行度高。
- 考虑了容灾域的隔离,能够实现各类负载的副本放置规则,例如跨机房、机架感知等。
- 能够支持上千个存储节点的规模,支持TB到PB级的数据。
高可用性
- 副本数可以灵活控制。
- 支持故障域分隔,数据强一致性。
- 多种故障场景自动进行修复自愈。
- 没有单点故障,自动管理。
高可扩展性
- 去中心化。
- 扩展灵活。
- 随着节点增加而线性增长。
特性丰富
- 支持三种存储接口:块存储、文件存储、对象存储。
- 支持自定义接口,支持多种语言驱动。
Ceph 体系结构
Ceph 基础组件
构成 ceph 集群的基础组件:OSD、Manager、MDS、Monitor。
-
OSD(ceph-osd)
:object storage daemon,对象存储进程。ceph 管理物理硬盘时,引入了OSD概念,每一块盘都会针对的运行一个OSD进程。换句话说,ceph 集群通过管理 OSD 来管理物理硬盘。OSD 一般功能为:存储数据、维护数据副本、数据恢复、数据再平衡以及对ceph monitor组件提供相关监控信息。 -
Manager(ceph-mgr)
:用于收集ceph集群状态、运行指标,比如存储利用率、当前性能指标和系统负载。对外提供 ceph dashboard(ceph ui)和 resetful api。Manager组件开启高可用时,至少2个。 -
Monitor(ceph-mon)
:维护集群的状态,包含monitor组件信息,manger 组件信息,osd组件信息,mds组件信息,crush 算法信息。还负责ceph集群的身份验证功能,client在连接ceph集群时通过此组件进行验证。Monitor组件开启高可用时,至少3个。 -
MDS(ceph-mds)
:Metadata server,元数据服务。为ceph 文件系统提供元数据服务(ceph 对象存储和块存储不需要MDS)。为 posix 文件系统用户提供性能良好的基础命令(ls,find等)。
创建Ceph 存储,至少需要以下服务:
- 一个Ceph Monitor
- 两个OSD守护进程
Ceph IO算法流程
File
是用户需要读写的文件。File->Object映射:
- ino (File的元数据,File的唯一id)。
- ono(File切分产生的某个object的序号,默认以4M切分一个块大小)。
- oid(object id: ino + ono)。
Object
是RADOS需要的对象。Ceph指定一个静态hash函数计算oid的值,将oid映射成一个近似均匀分布的伪随机值,然后和mask按位相与,得到pgid。Object->PG映射:
- hash(oid) & mask-> pgid 。
- mask = PG总数m(m为2的整数幂)-1 。
PG(Placement Group)
用于对object的存储进行组织和位置映射, (类似于redis cluster里面的slot的概念) 一个PG里面会有很多object。采用CRUSH算法,将pgid代入其中,然后得到一组OSD。PG->OSD映射:
- CRUSH(pgid)->(osd1,osd2,osd3) 。
OSD(Object Storage Device)
对象存储设备:物理或逻辑存储单元(如LUN)。有时,Ceph用户使用术语“OSD”来指代Ceph OSD守护进程,尽管正确的术语是“Ceph OSD”。
Ceph IO伪代码流程
locator = object_name
obj_hash = hash(locator)
pg = obj_hash % num_pg
osds_for_pg = crush(pg) # returns a list of osds
primary = osds_for_pg[0]
replicas = osds_for_pg[1:]
参考文档:
部署Ceph集群
Ceph 集群架构
使用ceph-deploy部署nautilus版Ceph
- 3个Ceph Monitor
- 3个Ceph OSD
环境准备
主机名 | IP | 配置 |
---|---|---|
ceph01 | 10.0.0.14 | 1核1G,额外硬盘sdb单个文件50G |
ceph02 | 10.0.0.15 | 1核1G,额外硬盘sdb单个文件50G |
ceph03 | 10.0.0.16 | 1核1G,额外硬盘sdb单个文件50G |
-
关闭:
selinux
,firewalld
和NetworkManager
,postfix
(非必须) -
修改IP地址、主机名
hostnamectl set-hostname 主机名
sed -i 's/200/IP/g' /etc/sysconfig/network-scripts/ifcfg-eth0
- 添加hosts解析
tee /etc/hosts <<-EOF
10.0.0.14 ceph01
10.0.0.15 ceph02
10.0.0.16 ceph03
EOF
- 如果热添加硬盘,需要扫描发现硬盘
echo '- - -' >/sys/class/scsi_host/host0/scan
echo '- - -' >/sys/class/scsi_host/host1/scan
echo '- - -' >/sys/class/scsi_host/host2/scan
fdisk -l
- 准备yum源:Base epel ceph
curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo
curl -o /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo
cat > /etc/yum.repos.d/ceph.repo <<EOF
[ceph_x86]
name=ceph_x86
baseurl=https://mirrors.tuna.tsinghua.edu.cn/ceph/rpm-nautilus/el7/x86_64/
gpgcheck=0
[ceph_noarch]
name=ceph_noarch
baseurl=https://mirrors.tuna.tsinghua.edu.cn/ceph/rpm-nautilus/el7/noarch/
gpgcheck=0
EOF
如果你想保留rpm的话,可以开启缓存。
vim /etc/yum.conf ... ... keepcache=1 # 开启缓存 ......
ceph-deploy节点
- 配置ssh密钥免密登录所有节点
ssh-keygen
ssh-copy-id root@ceph01
ssh-copy-id root@ceph02
ssh-copy-id root@ceph03
注意: 如果SSH不使用默认22端口时
cat > ~/.ssh/config <<EOF Port 12345 EOF
- 安装ceph-deploy
yum install ceph-deploy -y
所有节点安装
yum install ceph ceph-mon ceph-mgr ceph-radosgw.x86_64 ceph-mds.x86_64 ceph-osd.x86_64 -y
mkdir ceph_rpm
find /var/cache/yum -type f -name "*.rpm" | xargs mv -t ceph_rpm
tar zcf ceph_rpm.tar.gz ceph_rpm
scp ceph_rpm.tar.gz root@ceph02:/root
scp ceph_rpm.tar.gz root@ceph03:/root
ceph-deploy使用其内置官网源安装,非常慢!!!因此要提前装好所需包。
ceph-deploy部署ceph集群
- ceph01初始化集群配置文件
cd /root
mkdir ceph-deploy && cd ceph-deploy
ceph-deploy new --public-network 10.0.0.0/24 ceph01 ceph02 ceph03
默认
[--cluster-network CLUSTER_NETWORK]=[--public-network PUBLIC_NETWORK]
- 初始化集群:部署ceph-monitor并启动
ceph-deploy mon create-initial
在各节点生成配置文件
/etc/ceph
- 创建管理员用户:生成并推送管理员密钥
ceph-deploy admin ceph01 ceph02 ceph03
- 查看集群状态:mon存在
ceph -s
- 部署ceph-manager并启动
ceph-deploy mgr create ceph01 ceph02 ceph03
- 查看集群状态:mon和mgr存在
ceph -s
- 创建osd
ceph-deploy osd create ceph01 --data /dev/sdb
ceph-deploy osd create ceph02 --data /dev/sdb
ceph-deploy osd create ceph03 --data /dev/sdb
data:数据盘路径
journal:日志盘路径,日志盘越快,ceph越快。尤其是小块数据I/O,提速明显。
- 查看集群状态:mon和mgr和osd存在
ceph -s
如果状态有健康警告如下:
[root@ceph01 ceph-deploy]# ceph -s cluster: id: a4f16e95-ba09-49f5-b0bf-ada31833a457 health: HEALTH_WARN clock skew detected on mon.ceph03 services: mon: 3 daemons, quorum ceph01,ceph02,ceph03 (age 23m) mgr: ceph01(active, since 53m), standbys: ceph02, ceph03 osd: 3 osds: 3 up (since 29m), 3 in (since 29m) data: pools: 0 pools, 0 pgs objects: 0 objects, 0 B usage: 3.0 GiB used, 147 GiB / 150 GiB avail pgs:
生产环境请使用ntp服务!
测试环境可以调整ceph配置中的[global]下时间偏差阈值:
cat >> /root/ceph-deploy/ceph.conf <<EOF mon clock drift allowed = 2 mon clock drift warn backoff = 30 EOF
向所有同步的mon节点推送配置文件,重启mon服务:
ceph-deploy --overwrite-conf config push ceph0{1,2,3} systemctl restart ceph-mon.target
最后查看集群状态:HEALTH_OK
- 查看monitors信息
ceph mon dump
ceph 资源配置
- 创建pool资源池
ceph osd pool create k8s 128 128
- 查看pool资源池
ceph osd pool ls
ceph osd pool stats k8s
- 调整pool资源池的ps数量
ceph osd pool set k8s pg_num 128
- 创建RBD块设备
rbd create --size 1024 k8s/tomcat_mysql.img
- 查看RBD块设备
rbd info k8s/tomcat_mysql.img
rbd info --pool k8s tomcat_mysql.img
rbd info --pool k8s --image tomcat_mysql.img
- 查看OSD节点数量
ceph osd pool get k8s size
增加OSD节点会自动进行数据整合,请在业务低谷期间增加,一台一台慢慢加。
- 查看RBD块设备所有对象
rados -p k8s ls
rados -p k8s ls | grep rbd_data.ac74b202ed1a
rados -p k8s ls | grep rbd_data.ac74b202ed1a | wc -l
用多少,分多少。
- 树状显示所有OSD
ceph osd tree
使用RBD块设备
- 禁用高级特性
rbd feature disable k8s/tomcat_mysql.img object-map fast-diff deep-flatten
- 映射到实际设备
rbd map k8s/tomcat_mysql.img
/dev/rbd0
关机映射失效,需要重新映射,数据不会丢失。
- 格式化
mkfs.xfs /dev/rbd0
- 挂载
mount /dev/rbd0 /mnt
- 卸载
umount /mnt
- 扩容
rbd resize --size 2048 k8s/tomcat_mysql.img
- 挂载
mount /dev/rbd0 /mnt
- 调整容量
xfs_growfs /dev/rbd0
- 挂载,查看
df -Th
Ceph 对接 k8s
Ceph RBD 对接 k8s :参考官方文档
准备
所有k8s node节点安装ceph-common
cat > /etc/yum.repos.d/ceph.repo <<EOF
[ceph_x86]
name=ceph_x86
baseurl=https://mirrors.tuna.tsinghua.edu.cn/ceph/rpm-nautilus/el7/x86_64/
gpgcheck=0
[ceph_noarch]
name=ceph_noarch
baseurl=https://mirrors.tuna.tsinghua.edu.cn/ceph/rpm-nautilus/el7/noarch/
gpgcheck=0
EOF
yum -y install ceph-common
ceph01
- 推送ceph用户密钥文件和配置文件给所有k8s node节点
scp -rp /etc/ceph/ceph.client.admin.keyring root@10.0.0.12:/etc/ceph/
scp -rp /etc/ceph/ceph.client.admin.keyring root@10.0.0.13:/etc/ceph/
scp -rp /etc/ceph/ceph.conf root@10.0.0.12:/etc/ceph/
scp -rp /etc/ceph/ceph.conf root@10.0.0.13:/etc/ceph/
- 获取base64加密的ceph用户key
grep key /etc/ceph/ceph.client.admin.keyring |awk '{printf "%s", $NF}'|base64
- 创建最小特性镜像
rbd create --size 2048 --image-feature layering k8s/test.img
rbd ls -p k8s
k8s-master
- master节点编写Secret资源yaml
mkdir -p /k8s_yml/ceph && cd /k8s_yml/ceph
cat > /k8s_yml/ceph/ceph-secret.yaml <<EOF
apiVersion: v1
kind: Secret
metadata:
namespace: tomcat
name: ceph-secret
type: "kubernetes.io/rbd"
data:
key: QVFCQzNkUmZsL0tPQWhBQUV5L1g5a2NHb0NTTkJKclZVS0xXekE9PQ==
EOF
- master节点创建Secret资源
kubectl create namespace tomcat
kubectl create -f ceph-secret.yaml
- master节点查看Secret资源
kubectl get secret -n tomcat
- master节点查看Secret资源配置文件
kubectl get secret -n tomcat ceph-secret -o yaml
能看到ceph用户key,可以解密。
pod 对接ceph rbs存储
查看计划信息
kubectl explain pod.spec.volumes.rbd
- master节点编写Pod资源yaml
cat > /k8s_yml/ceph/test_ceph_pod.yaml <<EOF
apiVersion: v1
kind: Pod
metadata:
namespace: tomcat
name: rbd
spec:
containers:
- image: 10.0.0.11:5000/nginx:1.13
name: rbd-rw
volumeMounts:
- name: rbdpd
mountPath: /data
volumes:
- name: rbdpd
rbd:
monitors:
- '10.0.0.14:6789'
- '10.0.0.15:6789'
- '10.0.0.16:6789'
pool: k8s
image: test.img
fsType: ext4
user: admin
keyring: /etc/ceph/keyring
secretRef:
name: ceph-secret
EOF
- master节点创建Pod资源
kubectl create -f test_ceph_pod.yaml
- master节点查看Pod资源
kubectl get pod -o wide -n tomcat
- master节点进入容器,查看有/dev/rbd0设备,验证对接成功
kubectl exec -n tomcat -it rbd /bin/bash
df -h
- node节点查看所有映射的rbd
rbd device ls
pv 对接ceph rbs存储
- master节点编写PV资源yaml
cat > /k8s_yml/ceph/ceph_pv1.yaml <<EOF
apiVersion: v1
kind: PersistentVolume
metadata:
name: ceph01
labels:
type: rbd
spec:
capacity:
storage: 10Gi
accessModes:
- ReadWriteMany
persistentVolumeReclaimPolicy: Recycle
rbd:
monitors:
- '10.0.0.14:6789'
- '10.0.0.15:6789'
- '10.0.0.16:6789'
pool: k8s
image: test2.img
fsType: xfs
user: admin
secretRef:
name: ceph-secret
EOF
注意:请使用xfs格式。
ext4格式默认创建一个lost+found目录,导致mysql无法启动。
需要手动删除
df -Th|grep rbd rm -fr /var/lib/kubelet/plugins/kubernetes.io/rbd/rbd/k8s-image-test2.img/*
或者使用initContainer配置项,参考文档
- ceph创建最小特性镜像
rbd create --size 2048 --image-feature layering k8s/test.img
rbd ls -p k8s
- master节点创建pv资源
kubectl create -f ceph_pv1.yaml
- master节点查看pv资源
kubectl get pv -o wide
- master节点编写PVC资源yaml
cat > /k8s_yml/ceph/ceph_pvc.yaml <<EOF
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: tomcat-rbd1
namespace: tomcat
spec:
selector:
matchLabels:
type: rbd
accessModes:
- ReadWriteMany
resources:
requests:
storage: 10Gi
EOF
- master节点创建pvc资源
kubectl create -f ceph_pvc.yaml
- master节点查看pvc资源
kubectl get pvc -n tomcat -o wide
- master节点编写Deployment资源yaml
cat > /k8s_yml/ceph/mysql-deploy.yaml <<EOF
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
namespace: tomcat
name: mysql
spec:
replicas: 1
template:
metadata:
labels:
app: mysql
spec:
volumes:
- name: mysql
persistentVolumeClaim:
claimName: tomcat-rbd1
containers:
- name: wp-mysql
image: 10.0.0.11:5000/mysql:5.7
imagePullPolicy: IfNotPresent
ports:
- containerPort: 3306
volumeMounts:
- mountPath: /var/lib/mysql
name: mysql
env:
- name: MYSQL_ROOT_PASSWORD
value: '123456'
EOF
- master节点创建Deployment资源
kubectl create -f mysql-deploy.yaml
- master节点查看Deployment资源
kubectl get pod -n tomcat -o wide
Jenkins实现k8s持续更新
环境准备
主机名 | IP | 服务 | 内存 |
---|---|---|---|
k8s-master | 10.0.0.11 | kube-apiserver 8080 | 1G |
k8s-node-1 | 10.0.0.12 | kube-apiserver 8080 | 1G |
k8s-node-2 | 10.0.0.13 | Jenkins(tomcat + jdk) 8080 | 2G |
- 代码仓库使用gitee托管
gitee仓库准备
- 创建远程仓库
- Git 全局设置:
git config --global user.name "刘朋辉"
git config --global user.email "15094034633@163.com"
- 新仓库:
mkdir oldboy
cd oldboy
git init
touch README.md
git add README.md
git commit -m "first commit"
git remote add origin https://gitee.com/stronger-DAWEI/oldboy.git
git push -u origin master
- 已有仓库:
cd /opt
git remote remove origin
git remote add origin https://gitee.com/stronger-DAWEI/oldboy.git
git push -u origin master
jenkins部署(k8s-node-2)
- 准备Jenkins + tomcat + jdk
cd /opt
for n in apache-tomcat-8.0.27.tar.gz jdk-8u102-linux-x64.rpm jenkin-data.tar.gz jenkins.war;do wget http://192.168.15.253/k8s_jenkins/$n ;done
- 二进制安装jenkins
rpm -ivh jdk-8u102-linux-x64.rpm
mkdir /app -p
tar xf apache-tomcat-8.0.27.tar.gz -C /app
rm -fr /app/apache-tomcat-8.0.27/webapps/*
mv jenkins.war /app/apache-tomcat-8.0.27/webapps/ROOT.war
tar xf jenkin-data.tar.gz -C /root
/app/apache-tomcat-8.0.27/bin/startup.sh
netstat -lntup
jenkins构建测试
- 访问jenkins:http://10.0.0.13:8080/,默认账号密码 admin:123456
- 创建一个新任务
- 配置jenkins拉取gitlab代码凭据
- 构建Shell测试
- 立即构建
- 查看控制台输出
构建docker镜像node01
-
docker镜像底包:nginx:1.13 nginx nginx+php tomcat
-
编写
dockerfile
和.dockerignore
并运行测试
cat > dockerfile <<EOF
FROM 10.0.0.11:5000/nginx:1.13
RUN rm -rf /usr/share/nginx/html/*
ADD . /usr/share/nginx/html
EOF
echo dockerfile > .dockerignore
docker build -t test:v1 .
docker run -d -p 80:80 test:v1
-
浏览器访问:http://10.0.0.12/
-
上传
dockerfile
和.dockerignore
到私有仓库
git add .dockerignore dockerfile
git commit -m "add dockerfile"
git push -u origin master
-
gitee添加标签v1,修改首页,添加标签v2
-
master节点手动发布
kubectl create namespace oldboy
kubectl run -n oldboy oldboy --image=10.0.0.11:5000/oldboy:v1 --replicas=2
kubectl expose -n oldboy deploy oldboy --type=NodePort --port=80 --target-port=80
kubectl get all -n oldboy
kubectl set image -n oldboy deploy oldboy oldboy=10.0.0.11:5000/oldboy:v2
jenkins滚动更新
- 使用参数构建
- 修改Shell
docker build -t 10.0.0.11:5000/oldboy:$version .
docker push 10.0.0.11:5000/oldboy:$version
kubectl -s 10.0.0.11:8080 set image -n oldboy deploy oldboy oldboy=10.0.0.11:5000/oldboy:$version
- 执行测试
Build with Parameters --> 输入版本 --> 开始构建
jenkins从gitee下载代码,构建docker镜像并上传到私有仓库,调用k8s滚动发布。
- 查看控制台输出
- shell脚本
if [ -f /tmp/oldboy.lock ];then
docker build -t 10.0.0.11:5000/oldboy:v$version .
docker push 10.0.0.11:5000/oldboy:v$version
kubectl -s 10.0.0.11:8080 set image -n oldboy deploy oldboy oldboy=10.0.0.11:5000/oldboy:v$version
port=`kubectl -s 10.0.0.11:8080 get svc -n oldboy|grep -oP '(?<=80:)\d+'`
echo "你的项目地址访问是http://10.0.0.13:$port"
echo "更新成功"
else
docker build -t 10.0.0.11:5000/oldboy:v$version .
docker push 10.0.0.11:5000/oldboy:v$version
kubectl -s 10.0.0.11:8080 create namespace oldboy
kubectl -s 10.0.0.11:8080 run oldboy -n oldboy --image=10.0.0.11:5000/oldboy:v$version --replicas=3 --record
kubectl -s 10.0.0.11:8080 expose -n oldboy deployment oldboy --port=80 --type=NodePort
port=`kubectl -s 10.0.0.11:8080 get svc -n oldboy|grep -oP '(?<=80:)\d+'`
echo "你的项目地址访问是http://10.0.0.13:$port"
echo "发布成功"
touch /tmp/oldboy.lock
chattr +i /tmp/oldboy.lock
fi
jenkins一键回滚
另建一个工程,不需要拉代码,仅仅需要指定版本参数和shell,参数化回滚:
kubectl -s 10.0.0.11:8080 set image -n oldboy deploy oldboy oldboy=10.0.0.11:5000/oldboy:$version
k8s高可用
架构
主机名 | IP | 服务 |
---|---|---|
k8s-master01 | 10.0.0.11 | api-server,controller-manager,scheduler,etcd,keepalived,flannel |
k8s-master02 | 10.0.0.12 | api-server,controller-manager,scheduler,etcd,keepalived,flannel |
k8s-node-1 | 10.0.0.13 | kubernetes-node,flannel |
etcd高可用集群
不能单机扩集群,首次使用请使用集群,集群是奇数个,竞选。(虚拟机请还原快照)
- 所有节点安装
yum install etcd -y
- 所有节点配置
#[Member] #ETCD_CORS="" ETCD_DATA_DIR="/var/lib/etcd/" #ETCD_WAL_DIR="" ETCD_LISTEN_PEER_URLS="http://0.0.0.0:2380" ETCD_LISTEN_CLIENT_URLS="http://0.0.0.0:2379" #ETCD_MAX_SNAPSHOTS="5" #ETCD_MAX_WALS="5" ETCD_NAME="node1" # 节点的名字 #ETCD_SNAPSHOT_COUNT="100000" #ETCD_HEARTBEAT_INTERVAL="100" #ETCD_ELECTION_TIMEOUT="1000" #ETCD_QUOTA_BACKEND_BYTES="0" #ETCD_MAX_REQUEST_BYTES="1572864" #ETCD_GRPC_KEEPALIVE_MIN_TIME="5s" #ETCD_GRPC_KEEPALIVE_INTERVAL="2h0m0s" #ETCD_GRPC_KEEPALIVE_TIMEOUT="20s" # #[Clustering] ETCD_INITIAL_ADVERTISE_PEER_URLS="http://10.0.0.11:2380" # 节点同步数据的地址 ETCD_ADVERTISE_CLIENT_URLS="http://10.0.0.11:2379" # 节点提供服务的地址 #ETCD_DISCOVERY="" #ETCD_DISCOVERY_FALLBACK="proxy" #ETCD_DISCOVERY_PROXY="" #ETCD_DISCOVERY_SRV="" ETCD_INITIAL_CLUSTER="node1=http://10.0.0.11:2380,node2=http://10.0.0.12:2380,node3=http://10.0.0.13:2380" # 初始化集群 ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster" # 初始化集群令牌 ETCD_INITIAL_CLUSTER_STATE="new" # 初始化集群状态
cat > /etc/etcd/etcd.conf <<EOF
#[Member]
#ETCD_CORS=""
ETCD_DATA_DIR="/var/lib/etcd/"
#ETCD_WAL_DIR=""
ETCD_LISTEN_PEER_URLS="http://0.0.0.0:2380"
ETCD_LISTEN_CLIENT_URLS="http://0.0.0.0:2379"
#ETCD_MAX_SNAPSHOTS="5"
#ETCD_MAX_WALS="5"
ETCD_NAME="node1"
#ETCD_SNAPSHOT_COUNT="100000"
#ETCD_HEARTBEAT_INTERVAL="100"
#ETCD_ELECTION_TIMEOUT="1000"
#ETCD_QUOTA_BACKEND_BYTES="0"
#ETCD_MAX_REQUEST_BYTES="1572864"
#ETCD_GRPC_KEEPALIVE_MIN_TIME="5s"
#ETCD_GRPC_KEEPALIVE_INTERVAL="2h0m0s"
#ETCD_GRPC_KEEPALIVE_TIMEOUT="20s"
#
#[Clustering]
ETCD_INITIAL_ADVERTISE_PEER_URLS="http://10.0.0.11:2380"
ETCD_ADVERTISE_CLIENT_URLS="http://10.0.0.11:2379"
#ETCD_DISCOVERY=""
#ETCD_DISCOVERY_FALLBACK="proxy"
#ETCD_DISCOVERY_PROXY=""
#ETCD_DISCOVERY_SRV=""
ETCD_INITIAL_CLUSTER="node1=http://10.0.0.11:2380,node2=http://10.0.0.12:2380,node3=http://10.0.0.13:2380"
ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster"
ETCD_INITIAL_CLUSTER_STATE="new"
#ETCD_STRICT_RECONFIG_CHECK="true"
#ETCD_ENABLE_V2="true"
#
#[Proxy]
#ETCD_PROXY="off"
#ETCD_PROXY_FAILURE_WAIT="5000"
#ETCD_PROXY_REFRESH_INTERVAL="30000"
#ETCD_PROXY_DIAL_TIMEOUT="1000"
#ETCD_PROXY_WRITE_TIMEOUT="5000"
#ETCD_PROXY_READ_TIMEOUT="0"
#
#[Security]
#ETCD_CERT_FILE=""
#ETCD_KEY_FILE=""
#ETCD_CLIENT_CERT_AUTH="false"
#ETCD_TRUSTED_CA_FILE=""
#ETCD_AUTO_TLS="false"
#ETCD_PEER_CERT_FILE=""
#ETCD_PEER_KEY_FILE=""
#ETCD_PEER_CLIENT_CERT_AUTH="false"
#ETCD_PEER_TRUSTED_CA_FILE=""
#ETCD_PEER_AUTO_TLS="false"
#
#[Logging]
#ETCD_DEBUG="false"
#ETCD_LOG_PACKAGE_LEVELS=""
#ETCD_LOG_OUTPUT="default"
#
#[Unsafe]
#ETCD_FORCE_NEW_CLUSTER="false"
#
#[Version]
#ETCD_VERSION="false"
#ETCD_AUTO_COMPACTION_RETENTION="0"
#
#[Profiling]
#ETCD_ENABLE_PPROF="false"
#ETCD_METRICS="basic"
#
#[Auth]
#ETCD_AUTH_TOKEN="simple"
EOF
# node2
cat > /etc/etcd/etcd.conf <<EOF
#[Member]
#ETCD_CORS=""
ETCD_DATA_DIR="/var/lib/etcd/"
#ETCD_WAL_DIR=""
ETCD_LISTEN_PEER_URLS="http://0.0.0.0:2380"
ETCD_LISTEN_CLIENT_URLS="http://0.0.0.0:2379"
#ETCD_MAX_SNAPSHOTS="5"
#ETCD_MAX_WALS="5"
ETCD_NAME="node2"
#ETCD_SNAPSHOT_COUNT="100000"
#ETCD_HEARTBEAT_INTERVAL="100"
#ETCD_ELECTION_TIMEOUT="1000"
#ETCD_QUOTA_BACKEND_BYTES="0"
#ETCD_MAX_REQUEST_BYTES="1572864"
#ETCD_GRPC_KEEPALIVE_MIN_TIME="5s"
#ETCD_GRPC_KEEPALIVE_INTERVAL="2h0m0s"
#ETCD_GRPC_KEEPALIVE_TIMEOUT="20s"
#
#[Clustering]
ETCD_INITIAL_ADVERTISE_PEER_URLS="http://10.0.0.12:2380"
ETCD_ADVERTISE_CLIENT_URLS="http://10.0.0.12:2379"
#ETCD_DISCOVERY=""
#ETCD_DISCOVERY_FALLBACK="proxy"
#ETCD_DISCOVERY_PROXY=""
#ETCD_DISCOVERY_SRV=""
ETCD_INITIAL_CLUSTER="node1=http://10.0.0.11:2380,node2=http://10.0.0.12:2380,node3=http://10.0.0.13:2380"
ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster"
ETCD_INITIAL_CLUSTER_STATE="new"
#ETCD_STRICT_RECONFIG_CHECK="true"
#ETCD_ENABLE_V2="true"
#
#[Proxy]
#ETCD_PROXY="off"
#ETCD_PROXY_FAILURE_WAIT="5000"
#ETCD_PROXY_REFRESH_INTERVAL="30000"
#ETCD_PROXY_DIAL_TIMEOUT="1000"
#ETCD_PROXY_WRITE_TIMEOUT="5000"
#ETCD_PROXY_READ_TIMEOUT="0"
#
#[Security]
#ETCD_CERT_FILE=""
#ETCD_KEY_FILE=""
#ETCD_CLIENT_CERT_AUTH="false"
#ETCD_TRUSTED_CA_FILE=""
#ETCD_AUTO_TLS="false"
#ETCD_PEER_CERT_FILE=""
#ETCD_PEER_KEY_FILE=""
#ETCD_PEER_CLIENT_CERT_AUTH="false"
#ETCD_PEER_TRUSTED_CA_FILE=""
#ETCD_PEER_AUTO_TLS="false"
#
#[Logging]
#ETCD_DEBUG="false"
#ETCD_LOG_PACKAGE_LEVELS=""
#ETCD_LOG_OUTPUT="default"
#
#[Unsafe]
#ETCD_FORCE_NEW_CLUSTER="false"
#
#[Version]
#ETCD_VERSION="false"
#ETCD_AUTO_COMPACTION_RETENTION="0"
#
#[Profiling]
#ETCD_ENABLE_PPROF="false"
#ETCD_METRICS="basic"
#
#[Auth]
#ETCD_AUTH_TOKEN="simple"
EOF
# node3
cat > /etc/etcd/etcd.conf <<EOF
#[Member]
#ETCD_CORS=""
ETCD_DATA_DIR="/var/lib/etcd/"
#ETCD_WAL_DIR=""
ETCD_LISTEN_PEER_URLS="http://0.0.0.0:2380"
ETCD_LISTEN_CLIENT_URLS="http://0.0.0.0:2379"
#ETCD_MAX_SNAPSHOTS="5"
#ETCD_MAX_WALS="5"
ETCD_NAME="node3"
#ETCD_SNAPSHOT_COUNT="100000"
#ETCD_HEARTBEAT_INTERVAL="100"
#ETCD_ELECTION_TIMEOUT="1000"
#ETCD_QUOTA_BACKEND_BYTES="0"
#ETCD_MAX_REQUEST_BYTES="1572864"
#ETCD_GRPC_KEEPALIVE_MIN_TIME="5s"
#ETCD_GRPC_KEEPALIVE_INTERVAL="2h0m0s"
#ETCD_GRPC_KEEPALIVE_TIMEOUT="20s"
#
#[Clustering]
ETCD_INITIAL_ADVERTISE_PEER_URLS="http://10.0.0.13:2380"
ETCD_ADVERTISE_CLIENT_URLS="http://10.0.0.13:2379"
#ETCD_DISCOVERY=""
#ETCD_DISCOVERY_FALLBACK="proxy"
#ETCD_DISCOVERY_PROXY=""
#ETCD_DISCOVERY_SRV=""
ETCD_INITIAL_CLUSTER="node1=http://10.0.0.11:2380,node2=http://10.0.0.12:2380,node3=http://10.0.0.13:2380"
ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster"
ETCD_INITIAL_CLUSTER_STATE="new"
#ETCD_STRICT_RECONFIG_CHECK="true"
#ETCD_ENABLE_V2="true"
#
#[Proxy]
#ETCD_PROXY="off"
#ETCD_PROXY_FAILURE_WAIT="5000"
#ETCD_PROXY_REFRESH_INTERVAL="30000"
#ETCD_PROXY_DIAL_TIMEOUT="1000"
#ETCD_PROXY_WRITE_TIMEOUT="5000"
#ETCD_PROXY_READ_TIMEOUT="0"
#
#[Security]
#ETCD_CERT_FILE=""
#ETCD_KEY_FILE=""
#ETCD_CLIENT_CERT_AUTH="false"
#ETCD_TRUSTED_CA_FILE=""
#ETCD_AUTO_TLS="false"
#ETCD_PEER_CERT_FILE=""
#ETCD_PEER_KEY_FILE=""
#ETCD_PEER_CLIENT_CERT_AUTH="false"
#ETCD_PEER_TRUSTED_CA_FILE=""
#ETCD_PEER_AUTO_TLS="false"
#
#[Logging]
#ETCD_DEBUG="false"
#ETCD_LOG_PACKAGE_LEVELS=""
#ETCD_LOG_OUTPUT="default"
#
#[Unsafe]
#ETCD_FORCE_NEW_CLUSTER="false"
#
#[Version]
#ETCD_VERSION="false"
#ETCD_AUTO_COMPACTION_RETENTION="0"
#
#[Profiling]
#ETCD_ENABLE_PPROF="false"
#ETCD_METRICS="basic"
#
#[Auth]
#ETCD_AUTH_TOKEN="simple"
EOF
- 所有节点同时启动,并加入开机自启
systemctl enable etcd
systemctl start etcd
- 检查集群健康状态和成员列表
etcdctl cluster-health
etcdctl member list
flannel配置
- 修改配置文件
sed -i "4c FLANNEL_ETCD_ENDPOINTS="http://10.0.0.11:2379,http://10.0.0.12:2379,http://10.0.0.13:2379"" /etc/sysconfig/flanneld
- 创建key
etcdctl mk /atomic.io/network/config '{ "Network": "172.18.0.0/16","Backend": {"Type": "vxlan"} }'
- 启动并加入开机自启
systemctl start flanneld
systemctl enable flanneld
systemctl restart docker
- 检查网卡
ip a
master节点
master01和master02部署api-server,controller-manager,scheduler
- 安装
yum install kubernetes-master -y
- 配置apiserver
sed -i "8c KUBE_API_ADDRESS=\"--insecure-bind-address=0.0.0.0\"" /etc/kubernetes/apiserver
sed -i "11c KUBE_API_PORT=\"--port=8080\"" /etc/kubernetes/apiserver
sed -i "14c KUBELET_PORT=\"--kubelet-port=10250\"" /etc/kubernetes/apiserver
sed -i "17c KUBE_ETCD_SERVERS=\"--etcd-servers=http://10.0.0.11:2379,http://10.0.0.12:2379,http://10.0.0.13:2379\"" /etc/kubernetes/apiserver
sed -i "s/ServiceAccount,//" /etc/kubernetes/apiserver
- 配置config
sed -i "22c KUBE_MASTER=\"--master=http://127.0.0.1:8080\"" /etc/kubernetes/config
- 启动并加入开机启动
systemctl enable kube-apiserver.service
systemctl enable kube-controller-manager.service
systemctl enable kube-scheduler.service
systemctl restart kube-apiserver.service
systemctl restart kube-controller-manager.service
systemctl restart kube-scheduler.service
- 检查服务是否安装正常
kubectl get componentstatus
Keepalived配置
在master01和master02安装keepalived。
- 安装
yum install keepalived -y
- master01配置
cat > /etc/keepalived/keepalived.conf <<EOF
! Configuration File for keepalived
global_defs {
router_id LVS_DEVEL_11
}
vrrp_instance VI_1 {
state BACKUP
interface eth0
virtual_router_id 51
priority 100
advert_int 1
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
10.0.0.10
}
}
EOF
- master02配置
cat > /etc/keepalived/keepalived.conf <<EOF
! Configuration File for keepalived
global_defs {
router_id LVS_DEVEL_12
}
vrrp_instance VI_1 {
state BACKUP
interface eth0
virtual_router_id 51
priority 80
advert_int 1
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
10.0.0.10
}
}
EOF
- 启动并加入开机自启
systemctl enable keepalived
systemctl start keepalived
node节点
所有node节点的kubelet,kube-proxy指向api-server的vip。
- 安装:见k8s集群yum安装
- 配置
sed -i "22c KUBE_MASTER=\"--master=http://10.0.0.10:8080\"" /etc/kubernetes/config
sed -i "14c KUBELET_API_SERVER=\"--api-servers=http://10.0.0.10:8080\"" /etc/kubernetes/kubelet
- 重启生效
systemctl restart kubelet.service kube-proxy.service
kubectl get nodes
任意关掉一台进行测试