😁
运维笔记
运维笔记
运维笔记
  • Welcome my notes
  • PYTHON
    • Python 小技巧
      • Python阿里云余额TG报警
      • Python应知小技巧:如何用更少的代码做更多的事情
      • Python 使用缓存功能进行接口性能调优
      • 用pandas新建excel并设置表头
      • RBAC
      • Python读取文件去除回车
      • Python经过OpenSSL获取指定域名对应的SSL证书
      • Python爬取百度指数中的搜索指数
      • Python中反斜杠u类型(uXXXX)字符串转换为Unicode字符串
      • Python两种方式获取SSL证书信息
      • Python 项目环境变量方法
      • PYTHON 获得当前路径
      • Python 自动申请 SSL 证书
      • Python 拆分 URL
      • Python 谷歌令牌
      • Python redis 操作
      • Python 封装 Redis
      • dnspython实现NS记录查询
      • 2.7 版本 telegram 机器人
      • 最全的Python虚拟环境使用方法
      • hasattr、getattr和setattr的使用方法
      • 字符串与字节之间转换
      • 模块-文件共享-SimpleHTTPServer
      • 模块-文本变量-configparser
      • 模块-SSH连接-paramiko
      • HTTPS服务实现
      • 列表骚操作
      • PyMysql
      • 基础语法
      • 终端Print颜色
      • loguru日志库
      • 自动安装Nginx
      • Python3.7源码安装
      • linux 一键安装 conda
      • Pipenv常用的命令
      • 监听服务器的端口
      • 获取证书到期时间
      • 检测域名被墙污染
      • 发送电子邮件信息
      • 发送Telegram信息
      • 输出进度条的图形
      • Cloudflare DNS A记录自动更新脚本
      • Cloudflare-API操作
      • UUID库生成唯一ID
      • 静态方法、普通方法、类方法
      • 循环切片+多线程+消息队列queus
      • 注册 Forms
      • 循环切片+多线程+消息队列queus
      • Python 列表字符串转换整型
      • SQLAlchemy的查询分页和获取总条数
      • 使用shell和python分别实现简单菜单功能
      • 获取checkbox选中状态的两种方式
      • QQ爆红检测
      • 域名备案查询
      • 结合腾讯云发送短信
      • 爬虫神器PyQuery的使用方法
      • Dict 转换
      • 获取证书到期时间
      • 虚拟环境使用
      • 无限级分类的两种实现方式
      • 两个数组交集|并集|差集方法
      • https
      • ​统计代码耗时的几种方法
      • datetime库常用转换
      • datatime库计算当前时间||其他时间运算
      • 监控网站可用性并发送Telegram通知
      • 监控SSL证书可用性并发送Telegram通知
      • 监控端口可用性并发送Telegram通知
      • 自动下载阿里云OSS桶文件
      • 自动上传文件到阿里云OSS
      • 获取cpu,根据cpu数量分配线程数
      • 获取自己的公网IP地址
      • Pyhton检测邮箱是否可用
      • Python使用代理检测域名状态
    • Flask
      • Nginx 业务接口触发拉黑IP
      • 结合uWSGI和Nginx部署flask项目
      • pip错误
      • Flask请求扩展与中间件
      • Flask拦截器
      • Flask-SQLAlchemy批量插入数据性能测试
      • Flask-CeleryExt
      • Flask 级联删除
      • Flask-SQLAlchemy详解
      • Flask + Celery + Redis 异步发送邮件
      • Flask http异常捕获
      • Flask 自定义命令 类似于django的manage.py
      • Flask 项目中解决csrf攻击
      • Flask 视图请求钩子函数
      • 一、Pipenv管理项目
      • 二、摸版
      • 三、处理文件上传
      • 四、 Flask 定时任务
      • 五、REST架构API方法
      • 六、搭建查询IP地址接口
      • 七、Flask+Github触发webhoop接口
      • Flask用paginate实现数据分页
      • Flask 文件流下载
    • Django
      • Djanog admin 有用的设置
      • Django 下 redis 操作
      • Django Ninja
      • Django django-import-export
      • Django Admin自动填充当前用户的示例代码
      • 在Django Admin中为list_filter创建自定义过滤器
      • 1、Django基础一
      • 2、Django基础二
      • 3、Django后台基础用法
      • 4、Django缓存
      • 5、Django日志
      • 6、Django设置csrf_token
      • 7、Django图片上传前端显示
      • 8、Django全文搜索
      • 9、Django Queryset转Json
      • 10、Django开发||生产环境
      • 11、Django邮箱||验证码||登录
      • 12、Django解决扩展用户表时,后台ADMIN显示密码为明文的问题
      • 13、ORM批量添加||更新数据
      • 14、Django分页并前端显示
      • 15、Celery异步任务集成
      • 16、Django获取访问IP地址
      • 17、Django重定向返回上一页
      • 18、Django自定义页面跳转链接
      • 19、利用 django-simpleui 模板在管理后台添加自定义的菜单和自定义的页面、设置访问权限
      • 20、Django导入导出功能
      • 1000、Django错误
      • 21、Django3实现Websocket最简单demo
      • 22、打包django项目成exe文件
      • Vue+websocket+django实现WebSSH demo
      • 24、related_namerelated_query_name 的区别
    • DRF
      • permissions.py源码分析
      • DRF接口 + Vue实现下载文件
      • DRF基础笔记
      • API跨域设置
      • JWT多方式登录及自定义验证
    • Fastapi
      • 运维自动化之域名系统
      • 自定义异常
      • fastapi tortoise-orm 使用一
      • fastapi tortoise-orm 使用二
      • fastapi tortoise-orm 使用三
      • fastapi处理tortoise-orm异常
      • 基于FastAPI和Tortoise-ORM的WebSocket类的封装
      • FastAPI中使用调度程序执行异步任务,与Redis交互
      • Sqlalchemy异步操作
      • 第一个Fastapi
      • FastAPI 中间件
      • FastApi APIRouter引用
      • FastAPI 依赖注入
      • FastAPI 响应体模型及校验
      • FastAPI 项目结构优化
      • FastAPI 文件上传
      • FastAPI 数据库一对一
      • FastAPI 数据库一对多
      • FastAPI 数据库多对多
      • FastAPI 数据库创建
      • FastAPI 内部调用路径
      • FastAPI 请求参数及校验
      • FastAPI 请求模型及校验
      • FastAPI 内部调用路径
      • FastAPI 路径参数及校验
      • FastAPI 路径、请求、请求体综合使用
      • FastAPI 类视图
      • FastAPI 静态文件
      • FastAPI 接口文档配置相关
      • FastAPI 后台任务
      • FastAPI 更新数据
      • FastAPI 根据环境不同连接不同数据库
      • FastAPI 封装接口返回
      • FastAPI 日志
      • FastAPI 封装分页
      • FastAPI 端点调试
      • FastAPI 定制返回Response
      • FastAPI 操作数据库
      • FastAPI 部署 uvicorn + supervisor
      • FastAPI WebSocket
      • FastAPI startup 和 shutdown
      • FastAPI sql 转换 json
      • FastAPI Redis 操作
      • FastAPI OAuth2 认证
      • FastAPI Jwt 认证
      • FastAPI 表单使用
      • FastAPI Docker 方式
      • FastAPI CORS跨域
      • FastAPI Cookie 参数,Header参数
      • fastapi操作异步redis模块aioredis
      • RESTFUL API 访问和刷新令牌
    • PHP
      • thinkphp
        • 留言版系统
  • centos
    • Iptable
      • Firewalld使用ipset快速屏蔽指定国家的IP访问
      • Iptable 使用ipset设置防火墙端口白名单,只让指定国家访问
    • Minio
      • Minio 部署
      • Python 操作 minio
      • 挂载谷歌云盘
    • SSL
      • CentOS下自动申请、部署Let's Encrypt免费SSL证书教程(Nginx亲测)
    • Linux基操
      • 三次握手和四次挥手
      • Linux-性能常用命令
      • 常见DDOS攻击类型
      • Ubuntu配置IP及免密登录
      • Ubuntu 替换阿里云镜像
      • ntpdate 无法同步时间问题
      • linux下redis的使用
      • hey压测工具
      • Linux-Node安装
      • Linux-UFW设置
      • Linux-vsftp
      • Linux-小数点计算
      • Linux-内核升级
      • Linux-终端代理
      • Linux-输出字体颜色
      • Linux-SSH密钥登录
      • Linux-磁盘扩容缩容
      • Linux-设置时间时区
      • Linux-服务器入侵排查
      • Linux-增加Swap方法
      • Linux-vim可视化模式
      • Linux-Crontab定时任务
      • Linux-Supervisor进程管理
      • Linux-处理大量的 TIME_WAIT
      • awk|grep|sed|find
      • find常规用法
      • Linux-排查磁盘IO读写很高
      • Linux-排查CPU只用率很高
      • ubuntu搭建NFS服务
      • Centos7-yum问题
      • ubuntu 24.X 安装 python2.7
    • 科学上网
      • pptp
      • Sock5 代理
      • Goproxy 代理
      • Stunnel 加密 Squid 代理服务
      • MTProxy代理,专注Telegram
      • 使用一键脚本搭建L2TP+IPSec
    • Ansible
      • Ansible 部署 nginx
      • Ansible 部署 Supervisor
      • Ansible 基础笔记
      • 过滤器
      • ansible回调函数使用
      • 如何使用ansible来快速同步目录
      • Ansible 错误
      • Ansible 删除多个文件或目录
      • Ansible Api二次封装
      • Ansible 过滤器
      • Playbook 获取主机组主机数
      • Playbook 部署Squid代理
      • Playbook Debug用法
      • Playbook 部署Node_exporter
      • 批量安装Nginx
      • 安装K8S
      • Ansible如何通过跳板机连接目标机器
    • Git 教程
      • 首次使用
      • Git上传文件卡住无响应
      • Git速查表
      • Git 安装&配置
      • Git 创建仓库
      • Git 基本操作
      • Git 分支管理
      • Git 服务器搭建
      • Git基操-tag
      • Git修改远程仓库地址
      • Git clone速度太慢怎么办
      • Git 修改 tag 内容如何操作
      • Git 大文件上传
      • Github 创建新分支
    • Docker
      • containerd 安装
      • docker 镜像瘦身工具 docker-slim
      • Docker 与 IPtables
      • Page
      • Docker几种安装方式
      • Docker国内镜像加速
      • Docker容器自动启动设置
      • Docker使用Harbor无SSL
      • Docker使用Harbor的API
      • Dockerfile打包镜像优化
      • Docker自定义镜像查看日志方法
      • Dockerfile和docker-compose.yml设置时区
      • Swarm
        • 微服务架构部署问题
        • Swarm 基础命令
        • Swarm 安装使用
        • Swarm 服务版本更新|回滚
      • Docker-compose
        • Docker 镜像自动化部署
        • Prometheus+Grafana监控平台+钉钉报警
        • 基于Alpine构建php7+nginx(2)
        • 基于Alpine构建php7+nginx(1)
        • docker-compose mysql+django
        • docker-compose安装
        • docker compose升级
        • seata单节点或集群
        • 测试常用中间件快速启动
        • 开源监控-hertzbeat
      • Alpine构建镜像
        • 构建java镜像
        • Alpine-Timezone
        • Alpine-Redis
        • Alpine-Python
        • Alpine-Php
        • Alpine-Nginx
        • Alpine-Nginx-定制nginx
        • Alpine-Mysql
      • Page 3
      • Page 2
    • Shell
      • 批量远程执行命令脚本
      • Linux健康检查脚本
      • Page 1
      • 一键生成ssl自签名证书
      • 服务器日常巡检脚本
      • 生成100个随机6位数字
      • 9个实用 shell 脚本
      • 21 个非常实用的 Shell 拿来就用脚本实例
      • shell每秒执行一次
      • Shell脚本自动生成开头注释简介
      • Shell中$#、$0、set等的含义
      • Shell脚本书写规范
      • shell脚本里的变量怎么加一
      • Shell获取当前目录和上级目录
      • Nginx日志切割脚本(按天切割)
      • Redis源码安装脚本
      • Php源码安装脚本
      • Nginx 1.23.3 源码安装
      • Nginx 1.27.1 源码安装
      • MYSQL5.X源码安装脚本
      • Redis源码安装脚本
      • Lnmp各源码安装脚本
      • Linux打印系统配置信息脚本
      • expect交互
      • CentOS系统初始化脚本(适合CentOS 6.X和CentOS 7.X系列)
      • Ubuntu 系统初始化
      • Bash数组
      • 一键测试脚本bench.sh
      • 批量添加用户
      • Ftp-Python上传下载案例
      • Ftp-Mysql数据库全量自动备份删除7天前备份
      • Ftp-Mysql数据库的全量备份和增量备份脚本实例
      • Ftp-Python服务器
      • Shell脚本常用示例
      • Shell多进程模式
      • 管理Firewall防火墙脚本
      • MySQL5.7~8热备份
      • postgresql 库备份
    • Nginx
      • 一文搞定Nginx的压缩、黑白名单、防盗链、零拷贝、跨域、双机热备等知识
      • nginx 一把梭
      • 阿里云ESC的Nginx代理OSS
      • yum命令安装mariadb
      • Tengine安装lua
      • Nginx配置中的if判断
      • Nginx内置变量
      • nginx+php限制某个IP访问
      • Nginx 变量 set 使用方法
      • Nginx 判断值是否为空 设置变量 获取参数
      • lua随机值
      • 利用客户端随机跳转
      • JS代码简单的防封、防屏蔽、防举报、防红页面
      • Ngx_lua
      • WFT
      • 免费申请HTTPS六大方法
      • 502错误
      • Ngx基操
      • Ngx 配置文件实例
      • Ngx跨域解决方法
      • Ngx服务器内核优化
      • Ngx从安装到高可用
      • Ngx反向代理支持WSS
      • Ngx配置用户名密码访问
      • Ngx配置Http(s)|WS|WSS
      • Ngx算法|Rewrite规则|优先级
      • Ngx中websocket服务的配置
      • mp4
      • 跨域设置
      • Ngx 第三方库 ngx_brotli
      • Ngx 反向代理缓存规则
      • Ngx 反向代理禁用缓存
      • Logrotate实现nginx日志切割
    • Tomcat
      • nginx 前端https +tomcat 后端 http 非80、443端口反向代理的配置方式
      • Tomcat 8.x基于Redis Session会话保持
    • Keepalived
      • 高可用--Nginx+keepalived
      • 高可用-Haproxy+keepalived
      • 高可用-Lvs+Keepalived
    • Mysql
      • yum命令安装mariadb
      • ubuntu 首次安装mysql修改密码
      • 1、Yum安装MySql
      • 2、源码安装MYSQL5.7.21
      • 3、MYSQL主从冷备
      • 4、MYSQL主主热备
      • 5、Xtrabackup全备增备
      • 6、MYSQL管理员密码修改
      • 7、MYSQL字符集设置
      • 8、MYSQL命令整理
      • 9、MySQL数据导出csv格式
      • 10、MySQL根据日期查询数据的sql语句
      • 11、如何优雅备份MySQL?
      • 12、如何在已有的数据库中无损主主备份?
      • 13、PXC集群
      • 14、TIUP TIDB
      • 15、MySQL8.0锁情况排查
      • MYSQL 配置文件常用配置
      • Mysql 错误报错解决方法
      • 记录生产事故数据库被删
      • 压测 SQL 工具
    • Redis
      • Redis基操
      • Redis-cluster监控部署方案
    • Php
      • PHP项目迁移部署错误
      • 查找linux下进程占用CPU过高的原因,以php-fpm为例
    • Vscode
      • vscode实现远程linux服务器上Python开发
    • Prometheus
      • 使用 TLS 加密 Prometheus API 和 UI 端点
      • 使用基本身份验证保护 Prometheus API 和 UI 端点
      • 黑盒
      • prometheus
      • node-exporter https认证
      • 中文资料地址
      • 告警-微信
      • 告警-钉钉
      • 监控-基础指标
      • 监控-自定义指标
      • 黑盒-blackbox_exporter
      • 监控-平台搭建+邮件报警
      • Prometheus 监控 Redis
      • Prometheus 监控 NGINX
      • Prometheus 监控进程
      • PushGateway 数据上报采集
      • Prometheus 将数据远程写入 InfluxDB 存储
      • 外部Prometheus监控k8s集群资源
      • prometheus-Agent服务注册
      • Prometheus-自动发现监控 AWS EC2
      • Prometheus-黑盒blackbox
      • Prometheus-Pushgateway自定义
      • Prometheus-采集MySQL指标
      • Prometheus-采集Redis指标
      • Prometheus-采集Kafka指标
    • Vue
      • Vite解决开发、生产服务器的自动切换
      • js实现60秒倒计时
      • H5页面实现下载文件
      • loading加载动画
      • Vue如何新建一个项目
      • Vue开发菜单权限与按钮权限管理
      • Vue 错误
      • Vue开发必备插件
      • Vue如何新建一个项目
      • vue-router+nginx 非根路径配置方法
      • vue中配置proxy指定api请求地址
      • vue开发----关于字符串去除空格的方法
      • vue表格中动态更新,动态删除,动态添加
      • 项目
        • 1 01.创建 Vite项目并安装 Vscode 插件
        • 1 02.引入ElementPlus和基本使用
        • 1 03.引入windicss工具库和配置,安装代码提示
        • 1 04.引入vue router4路由配置和404页面捕获
        • 1 05.登录页图标引入响应式开发
        • 1 06.结合@apply实现样式抽离
        • 1 07.登录表单验证处理
        • 1 08.引入axios请求库和登录接口交互
        • 1 09.引入cookie存储用户token
        • 1 10.封装请求拦截器和响应拦截器及工具库
        • 1 11.引入vuex状态管理用户信息
        • 1 12.全局路由拦截实现登录判断
        • 1 13.登录功能完善
        • 1 14.退出功能实现
        • 2 01.全局loading进度条实现
        • 2 02.动态页面标题实现
        • 2 03.后台主布局实现
        • 2 04.公共头部开发 样式布局
        • 2 05.公共头部开发 刷新和全屏
        • 2 06.公共头部开发 修改密码
        • 2 07.封装通用弹框表单组件
        • 2 08.封装组合式api简化代码
        • 2 09.侧边菜单开发 样式布局和路由跳转
        • 2 10.展开和收起菜单功能实现
        • 2 11.菜单选中和路由关联
        • 2 12.根据菜单动态添加路由
        • 2 13.封装标签导航组件实现
        • 页面缓存实现
        • 2 15.transition全局过渡动画
        • 2 16.统计面板组件开发
        • 2 17.数字滚动动画实现
        • 2 18.分类组件开发和跳转
        • 2 19.echarts图表组件开发和交互
        • 2 20.店铺和交易提示组件开发和交互
        • 2 21.v permission指令按钮级权限控制
        • 2 22.封装上传多图组件功能实现
        • 2 23.公告栏模块Curd操作
        • 2 24.封装组合式API特性 列表分页搜索增删改
        • 2 25.封装自定义下拉图标组件
    • Bootstrap
      • jQuery判断数组中是否存在某个值的方法
      • jQuery 判断数组中是否包含某个值
      • jQuery checkbox选中和不选中的值_设置checkbox选中状态
      • BootStrap中关于Select下拉框选择触发事件
    • Zabbix
      • Zabbix_Agent
      • PY发送钉钉通知
      • 部署zabbix脚本
      • SHELL发送邮件
      • NGINX状态监控
      • Zabbix模板
    • CICD
      • Pipeline
        • Docker 容器服务重启
        • Docker 镜像打包发布回滚
      • Jenkins+Ansible-playbook自动发布回滚
      • Jenkins、GitLab部署
      • Docker+Nginx+Jenkins+GitLab实现前端自动化部署
      • Jenkins 版本回滚
      • Jenkins 自动化
      • GitLab
        • GitLab 安装
        • GitLab 不同版本迁移
        • GitLab 如何设置中文
    • Email 自建
      • mailcow
      • iRedMail 更改 Mail 域
      • poste.io
  • 消息队列
    • 消息队列选型
  • ES
    • 监控输出到ES错误日志告警
    • filebeat收集java日志
    • filebeat 快速安装
    • ELK配置之,filebeat更改自定义索引名称
    • ELK-Kafka-Filebeat
    • Docker 部署 3 节点 ES 集群
    • ElasticSearch Python操作
    • ElasticSearch常规操作
    • ElasticSearch 7.7.0(单机版)+ Ik 分词器 + ES-head 可视化插件
    • ES 常见错误
    • Grafana+ES+Nginx
    • ES-自动删除7天前索引日志
  • Ubuntu
    • Linux时间与系统时间相差8小时的解决办法
    • Ubuntu 重启网卡的三种方法
    • Ubuntu 网卡配置为静态方法
  • Java
  • 😘Kubernetes
    • k3s
      • K3s集群安装
      • Longhorn 分布式存储
      • kubesphere 管理界面
    • 常用 YAML 模板
      • external-mysql
      • cluster-nacos
      • cluster-xxl-job-admin
      • cluster-seata
      • singlenode-es
      • singlenode-mysql
      • storage-mysql
      • singlenode-rabbitmq
      • singlenode-redis
      • singlenode-sentinel
    • Rancher
      • Rke集群
      • RKE1.5.7安装集群
    • Etcd
      • Docker-单节点单Etcd部署
      • Docker-单节点多Etcd部署
      • Docker-多节点Etcd部署
      • CronJob资源控制器进行定时备份
      • 生产环境ETCD高可用集群
    • Ceph
      • Docker-单节点,多OSD集群
      • Ansible-ceph集群
      • Docker-ceph集群
    • k8s
      • kubernetes 1.23.6
      • kubesphere
      • 使用kubeadm搭建高可用的K8s集群
      • 使用kubeadm快速部署一个K8s集群
      • Rancher+k3s
      • k3s执行helm命令报错Error Kubernetes cluster unreachable Get “httplocalhost8080versiontimeout=32s“
      • 尚硅谷k8s课堂随笔
      • kubernetes学习随笔
      • 问题
      • k8s清除环境脚本
      • Minikube单机版k8s实验环境
      • 常用中间件快速启动
      • kubeadm单机版k8s测试部署
      • kubeadm生产环节高可用部署
      • 跨VPC网络K8S
        • k8s无法删除namespace
        • 跨VPC网络-工具安装
        • 跨VPC网络-二进制ETCD集群
        • 跨VPC网络-使用 kubeadm 创建集群(v1.24)
        • 部署 metrics-server
      • K8s证书考试
    • Helm
      • Helm 安装 MongoDB-分片集群
      • Helm 安装 MongoDB-副本集群
      • helm 安装 rocketmq
      • helm 安装 MongoDB 集群
      • Helm 安装 Redis 集群
      • Helm 安装 Redis 哨兵主从高可用
      • Helm 安装
      • Helm安装Kafka
      • Helm同时部署多个域名
      • Helm内置对象和摸版语言
      • 如何使用github作为Helm的chart仓库
      • Helm 安装 Kubernetes 监控套件
    • 错误记录
      • kubelet启动报错
  • Go
    • 学习笔记
      • 1、Go环境安装
      • 2、Go目录结构及包管理
      • 3、Go的编译和运行
      • Gin 基础
      • Gin 项目实战
      • Go 基础
      • Gorm 基础
      • Go中&与的区别以及使用
      • myblog
    • 视频切片
    • 面试
      • 灵魂拷问
      • 面试稳了
      • 自己经历的面试问题总结
      • K线、均线、趋势、形态、N型反转
    • 错误
    • 小工具
      • 其他工具列表
      • 性能压力测试小工具 wrk
    • AWS
      • CDN缓存刷新
Powered by GitBook
On this page
  • 第一部分 K8S基本概念
  • 1. K8S概述和特性
  • 2. K8S架构组件
  • 3. K8S核心概念
  • 4. 集群 YML 文件详解
  • 5. kubectl 命令集合
  • 第二部分 搭建K8S集群
  • 方法一:使用 kubeadm方式搭建k8s集群
  • 方法二:二进制方式
  • 第三部分 K8S核心技术
  • 1. Pod
  • 2. Controller
  • 3. Service
  • 4. 无状态和有状态
  • 5 计划任务
  • 6. Secret
  • 7. 集群安全机制
  • 8. helm
  • 9. Yaml格式的pod定义文件完整内容
  • 10. NFS
  • 11. StorageClass
  • 第四部分 部署统一日志管理
  • 第五部分 部署性能监控平台
  • 第六部分 搭建高可用的K8S集群
  • 第七部分 K8S集群部署项目
  • 第八部分 Ceph 集群
  • 1、Cepy-deploy 部署
  • 2、ceph.conf
  • 扩展群集
  • 添加监视器
  • 添加管理员
  • 配置DashBoard
  • 常用命令整理
  • 对接 k8s 集群:Rbd 持久化存储 <已验证>
  • 对接k8s集群: Cephfs 持久化存储 <已验证>
  • 第九部分 常见问题
  • 技巧:无法删除 PV,PVC ?
  • 技巧: 无法删除 Pod ?
  • 技巧: kubeadm 如何删除节点?
  • 技巧:如何重启Pod?
  • 莫名被打上污点?
  • kubeadm安装的K8s忘记了token或者token过期了怎么办?
  • k8s.v1.20 NFS 无法动态创建pvc,Pending状态
  1. Kubernetes
  2. k8s

尚硅谷k8s课堂随笔

第一部分 K8S基本概念

1. K8S概述和特性

  • K8S是谷歌在2014年开业的容器化集群管理系统

  • 使用k8s进行容器化应用部署

  • 使用k8s利于应用扩展

  • k8s目标实施让部署容器化应用更加简洁和高效

2. K8S架构组件

​ Master(主控节点)和 node (工作节点)

  1. master 组件

    • apiserver ---> 集群统一入口,以 restfull 方式,交给 etcd 存储

    • scheduler ---> 节点调度,选择node节点应用部署

    • controller-manager ---> 处理集群中常规后台任务,一个资源对应一个控制器

    • etcd ---> 存储系统,保存集群相关的数据

  2. node组件

    • kubelet ---> master 派到 node 节点代理,管理本机容器

    • kube-proxy ---> 提供网络代理,负载均衡等操作

3. K8S核心概念

- Pod

  • 最小的部署单元

  • 一组容器的集合

  • 共享网络

  • 生命周期是短暂的

- controller

  • 确保预期的pod副本数量

  • 无状态应用部署

  • 有状态应用部署

  • 确保所有的 node 运行同一个 pod

  • 一次性任务和定时任务

- Service

  • 定义一组 pod 的访问规则

4. 集群 YML 文件详解

4.1 YAML 基本语法

  • 使用空格做为缩进

  • 缩进的空格数目不重要,只要相同层级的元素左侧对齐即可

  • 低版本缩进时不允许使用 Tab 键,只允许使用空格

  • 使用#标识注释,从这个字符一直到行尾,都会被解释器忽略

4.2 支持的数据结构

  • 对象; 键值对集合 -----( 映射/哈希/字典)

    name: Tom
    age: 18                  ===   hash: {name: Tom, age: 19}
  • 数组; 序列 ?列表

    People
    - Tom
    - Jack                    ===  People: [Tom, Jack]
  • 纯量( scalars ), 不可分的值

    number: 12.30       浮点数
    isSet: true         布尔值
    parent: ~           null 用 ~ 表示
    iso8601: 2001-12-14t21:59:43.10-05:00    时间采用 iso8601 格式
    date: 1976-07-31    日期
    字符串可以写成多行,第二行需有一个空格缩减

4.3 资源清单表述方法

4.3-1 YAML 必须存在的属性

参数名
字段类型
说明

version

String

api版本,目前v1, 可用kubect api-version查看

kind

String

定的资源类型和角色: 比如 Pod

metadata

Object

元数据对象,固定值 metadata

metadata.name

String

元数据对象名字

metadata.namespace

String

元数据命名空间

Spec

Object

详细定义对象,固定值写Spec

spec.containers[]

list

这是Spec对象的容器列表定义,是个列表

spec.containers[].name

String

定义容器的名字

spec.containers[].image

String

定义要用到的镜像名称

4.3-2 YAML Spec 主要对象

参数名
字段类型
说明

spec.containers[].imagePullPolicy

String

默认 Always; 定义镜像拉取策略,有Always(总是)、Never(使用本地)、IfNotPresent(如果本地没有就拉取);

spec.containers[].command[]

List

指定容器启动命令,可指定多个,不指定默认使用容器打包的启动命令

spec.containers[].args[]

List

指定容器启动参数,可指定多个

spec.containers[].workingDir

List

指定容器的工作目录

spec.containers[].volumeMounts[]

List

指定容器内部的存储卷配置

spec.containers[].valumeMounts[].name

String

指定可以被容器挂载的存储卷名称

spec.containers[].valumeMounts[].mountPath

String

指定可以被容器挂载的容器卷的路径

spec.containers[].valumeMounts[].readOnly

String

设置存储卷路径的读写模式,true或者false,默认为读写模式

spec.containers[].ports[]

List

指定容器需要用到的端口列表

spec.containers[].ports[].name

String

指定端口名称

spec.containers[].ports[].containerPort

String

指定容器需要监听的端口号

spec.containers[].ports.hostPort

String

指定容器所在主机需要监听的端口号,默认和 containerPort相同,如果设置了hostport,同一台主机无法启动相同副本,会冲突

spec.containers[].ports[].protocol

String

指定端口协议,TCP/UDP,默认TCP

spec.containers[].env[]

List

指定容器运行时需设置的环境变量列表

spec.containers[].env[].name

String

指定环境变量名称

spec.containers[].env[].value

String

指定环境变量值

spec.containers[].resources

Object

指定资源限制和资源请求的值(资源上限)

spec.containers[].resources.limits

Object

指定设置容器运行时资源的运行上限

spec.containers[].resources.limits.cpu

String

指定CPU限制,单位 core 数,将用于 --cpu-shares 参数

spec.containers[].resources.limits.memory

String

指定MEM内存限制,单位 MIB,GIB

spec.containers[].resources.requests

String

指定容器启动和调度室的限制设置

spec.containers[].resources.requests.cpu

String

CPU请求,单位 core 数,容器启动时初始化可用数量

spec.containers[].resources.requests.memory

String

内存请求,单位MIB,GIB,容器启动时初始化可用数量

4.3-3 YAML 额外的参数

参数名
字段类型
说明

spec.restarPolicy

String

定义Pod重启策略,可以选择值为Always、OnFailure,默认为Always. Always: Pod一旦终止运行,将重启它。 2.OnFilure ,只有Pod以非零退出码终止时,重启,否则,不重启。 3. Never: Pod终止后,将退出码报告给Mater,不会重启改Pod

spec.nodeSelector

Object

定义Node的Label过滤标签,以key:value格式指定

spec.imagePullSecrets

Object

定义pull镜像是使用secrets名称,以name:secretKey格式指定

spec.hostNetwork

Boolean

定义是否使用主机忘了默认,默认值false,设置true表示使用宿主机忘了,不适用docker网桥,同时设置true将无法在一台宿主机上启动第二个副本

4.3-4 举例说明

# 创建一个命名空间 namespace, 创建一个Pod
apiVersion: v1
kind: Namespace
metadata:
    name: test
---
apiVersion: v1
kind: Pod
metadata:
    name: pod1
spec:
    containers:
    - name: ningx-containers
      image: nginx:latest
kubectl get namespaces      # 查看命名空间
kubectl get pods            # 查看pod
kubectl describe pods/pod1  # 查看指定pod

5. kubectl 命令集合

5.1 基础命令解释

create
通过文件名或标准输入创建资源

expose

将一个资源公开为一个新的 Service

run

在集群中运行一个特定的镜像

set

在对象上设置特定的功能

get

显示一个或多个资源

expian

文档参考资料

edit

使用默认的编辑器编辑一个资源

delete

通过文件名、标准输入、资源名称或标签选择器来删除资源

5.2 部署和集群管理命令解释

rollout
管理资源的发布

rolling-update

对给定的复制控制器滚动更新

scale

扩容或缩容Pod数量,Deployment、ReplicaSet、RC或Job

autoscale

创建一个自动选择扩容和缩容并设置Pod数量

certificate

修改证书资源

cluster-info

显示集群信息

top

显示资源(CPU/Memory/Storage)使用

cordon

标记节点不可调度

uncordon

标记节点可调度

drain

驱逐节点上的应用,准备下线维护

taint

修改节点 taint 标记

5.3 故障和调试命令解释

describe
显示特定资源或资源组的详细信息

logs

在一个Pod中打印一个容器日志。如果Pod只有一个容器,容器名称是可选的

attach

附加到一个运行的容器

exec

执行命令到容器

port-forward

转发一个或多个本地端口到一个pod

cp

拷贝文件或目录到容器中

auth

检查授权

5.4 其他命令解释

apply
通过文件名或标准输入对资源应用配置

patch

使用补丁修改、更新资源的字段

replace

通过文件名或标准输入替换一个资源

convert

不同的API版本直接转换配置文件

label

更新资源上的标签

annotate

更新资源上的注释

completion

用于实现kubectl工具自动补全

api-version

打印受支持的API版本

config

修改kubeconfig文件(用户访问API,比如配置认证信息)

plugin

运行一个命令行插件

version

打印客户端和服务版本信息

help

帮助

5.5 如何跨省编写 yaml 文件

1、第一种 使用 kubectl create 命令生成 yaml 文件

kubectl create deploy web --image=nginx -o yaml --dry-run>my.yaml

2、第二中 使用 **kubectl get ** 命令导出yaml文件 ; <适用于已有部署集>

kubectl get deploy <部署集名字> -o yaml --export > my.yaml
# create 语法: kubectl create -f FILANEM [flags]  
  - kubectl create -f xx.yaml -f xx.yaml       # 创建资源 或 多个资源
  - kubectl create -f ./dir                    # 使用目录下所有 yaml 文件创建资源
  - kubectl create -f http://baidu.com/xxx.yaml# 使用 url 创建资源
  - kubectl create namespace myspace           # 创建名字为 myspace 的命名空间
  - kubectl delete namespace myspace           # 删除名字为 myspace 的命名空间

# expose 将副本控制器、服务或 pod 作为新的 Kubernetes 服务暴露 ,语法:
kubectl expose (-f FILENAME | TYPE NAME | TYPE/NAME) [–port=port] [–protocol=TCP|UDP] [–target-port=number-or-name] [–name=name] [–external-ip=external-ip-of-service] [–type=type] [flags]
  - kubect expose rc nginx --port=80 --tarport=8000     # 为副本控制器(rc)的nginx创建service,并通过service的80端口转发到容器的8000端口上
  - kubect expose -f xxx.yml       # 由xxx.yml中指定的type和name表示的RC创建Service,并通过service的80端口转发到容器的8000端口

# run 
kubectl run nginx --image=nginx                 # 启动nginx实例
kubectl run nginx --image=nginx --port=80       # 启动nginx实例,并暴露容器80端口
kubectl run nginx --image=nginx --replicas=5    # 启动nginx实例,设置副本数5
kubectl run nginx --image=nginx --env="DNS_DOMAIN=cluster" --env="POD_NAMESPACE=default" # 启动nginx实例,并设置变量

kubectl get namespaces                       # 查看所有命名空间及状态, 查看某一个,后面加上命名空间名字
kubectl describe namespaces <命名空间>        # 查看命名空间信息
kubectl create namespace <命名空间>           # 创建命名空间
kubectl create deploy <部署集名字> -image=nginx  --namespace=<名称空间名字>  # 在指定命名空间上部署应用
kubectl get deploy -n <命名空间>              # 查看命名空间下的部署集
kubectl delete deploy <部署集名字>            # 直接删除pod会触发部署集,重新创建pod,所以直接删除部署集
kubectl delete namespace <命名空间>           # 此操作会删除该命名空间下的所有资源
kubectl describe pods <pod名字> -n <命名空间> # 查看某个命名空间下某个pod的详细信息
kubectl logs <pod> -n <命名空间>              # 查看pod日志 

第二部分 搭建K8S集群

方法一:使用 kubeadm方式搭建k8s集群

1. 三台 Centos7.x 服务器

服务器
IP(需联网)

k8s-master

192.168.1.134

k8s-node01

192.168.1.135

k8s-node02

192.168.1.136

2. 所有节点初始化操作

# 关闭防火墙
systemctl stop firewalld
systemctl disable firewalld

# 关闭selinux   # 永久    # 临时
sed -i 's/enforcing/disabled/' /etc/selinux/config
setenforce 0

# 关闭swap   # 临时    # 永久
swapoff -a
sed -ri 's/.*swap.*/#&/' /etc/fstab

# 根据规划设置主机名
hostnamectl set-hostname <hostname>

# 只在master添加hosts
cat >> /etc/hosts << EOF
192.168.44.134 k8s-master
192.168.44.135 k8s-node01
192.168.44.136 k8s-node02
EOF

# 将桥接的IPv4流量传递到iptables的链
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 install ntpdate -y
ntpdate time.windows.com

3. 所有节点安装程序包

所有节点:docker 、kubelet 、kubeam 、kubctl

3.1 安装 Docker

yum install wget -y
wget https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo -O /etc/yum.repos.d/docker-ce.repo
yum -y install docker-ce-18.06.1.ce-3.el7
systemctl enable docker && systemctl start docker
docker --version
# 显示: Docker version 18.06.1-ce, build e68fc7a
# 由于国内服务器,拉取国外镜像过慢,配置镜像加速
cat > /etc/docker/daemon.json << EOF
{
  "registry-mirrors": ["https://b9pmyelo.mirror.aliyuncs.com"]
}
EOF

3.2 添加阿里云YUM软件源

cat > /etc/yum.repos.d/kubernetes.repo << EOF
[kubernetes]
name=Kubernetes
baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64
enabled=1
gpgcheck=0
repo_gpgcheck=0
gpgkey=https://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg https://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg
EOF

3.3 安装kubeadm,kubelet和kubectl

# 由于版本更新频繁,这里指定版本号部署:
yum install -y kubelet-1.18.0 kubeadm-1.18.0 kubectl-1.18.0
systemctl enable kubelet

4. Master 集群初始化

kubeadm init命令

# Master(192.168.1.134) 上执行, 其他ip端只要不冲突即可
kubeadm init \
  --apiserver-advertise-address=192.168.1.134 \
  --image-repository registry.aliyuncs.com/google_containers \
  --kubernetes-version v1.18.0 \
  --service-cidr=10.96.0.0/12 \
  --pod-network-cidr=10.244.0.0/16
# 初始化成功后,依据提示执行
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
kubectl get nodes

5. Node 节点添加到当前集群中

kubeadm join 192.168.1.134:6443 --token pvx7z8.ubvh64gsfv5l5tw0 \
    --discovery-token-ca-cert-hash sha256:c65c8e0f8e4f897bfdbe9160f69e380942e4d6e38e6690e435b5d2a4bd0d3294

6.所有节点配置网络插件

# wget https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml

kubectl get pods -n kube-system
NAME                          READY   STATUS    RESTARTS   AGE
kube-flannel-ds-amd64-2pc95   1/1     Running   0          72s

7. 测试kubernetes集群

# 在Master节点,在Kubernetes集群中创建一个pod,验证是否正常运行:
kubectl create deployment nginx --image=nginx
kubectl expose deployment nginx --port=80 --type=NodePort
kubectl get pod,svc

访问地址:http://NodeIP:Port  

方法二:二进制方式

1. 三台 Centos7.x 服务器

服务器
IP(需联网)

k8s-master

192.168.1.134

k8s-node01

192.168.1.135

k8s-node02

192.168.1.136

2. 所有节点初始化操作

# 关闭防火墙
systemctl stop firewalld
systemctl disable firewalld

# 关闭selinux   # 永久    # 临时
sed -i 's/enforcing/disabled/' /etc/selinux/config
setenforce 0

# 关闭swap   # 临时    # 永久
swapoff -a
sed -ri 's/.*swap.*/#&/' /etc/fstab

# 根据规划设置主机名
hostnamectl set-hostname <hostname>

# 只在master添加hosts
cat >> /etc/hosts << EOF
192.168.1.134 k8s-master
192.168.1.135 k8s-node01
192.168.1.136 k8s-node02
EOF

# 将桥接的IPv4流量传递到iptables的链
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 install ntpdate -y
ntpdate time.windows.com

3. 准备 cfssl 证书生成工具

wget https://pkg.cfssl.org/R1.2/cfssl_linux-amd64
wget https://pkg.cfssl.org/R1.2/cfssljson_linux-amd64
wget https://pkg.cfssl.org/R1.2/cfssl-certinfo_linux-amd64
chmod +x cfssl_linux-amd64 cfssljson_linux-amd64 cfssl-certinfo_linux-amd64
mv cfssl_linux-amd64 /usr/local/bin/cfssl
mv cfssljson_linux-amd64 /usr/local/bin/cfssljson
mv cfssl-certinfo_linux-amd64 /usr/bin/cfssl-certinfo

3.1 创建工作目录

mkdir -p ~/TLS/{etcd,k8s}
cd TLS/etcd

3.2 创建生成 Etcd Ca 证书配置

# 自签证书
cat << EOF | tee ca-config.json
{
  "signing": {
    "default": {
      "expiry": "87600h"
    },
    "profiles": {
      "www": {
         "expiry": "87600h",
         "usages": [
            "signing",
            "key encipherment",
            "server auth",
            "client auth"
        ]
      }
    }
  }
}
EOF

cat << EOF | tee ca-csr.json
{
    "CN": "etcd CA",
    "key": {
        "algo": "rsa",
        "size": 2048
    },
    "names": [
        {
            "C": "CN",
            "L": "Beijing",
            "ST": "Beijing"
        }
    ]
}
EOF

3.3 创建 ETCD Server申请文件

cat << EOF | tee server-csr.json
{
    "CN": "etcd",
    "hosts": [
    "192.168.1.134",
    "192.168.1.135",
    "192.168.1.136"
    ],
    "key": {
        "algo": "rsa",
        "size": 2048
    },
    "names": [
        {
            "C": "CN",
            "L": "Beijing",
            "ST": "Beijing"
        }
    ]
}
EOF

# 注:上述文件 hosts 字段中 IP 为所有 etcd 节点的集群内部通信 IP,一个都不能少!为了 方便后期扩容可以多写几个预留的 IP。

3.4 生成 Etcd HTTPS证书

# 生成自签Etcd CA 证书, 并使用自签 CA 签发 ETCD 证书
cfssl gencert -initca ca-csr.json | cfssljson -bare ca -
cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=www server-csr.json | cfssljson -bare server

ls ca*pem && ls server*pem

3.5 创建生成 kube-apiserver 配置

cd ~/TLS/k8s/

# 自签证书颁发机构(CA)
cat << EOF | tee ca-config.json
{
  "signing": {
    "default": {
      "expiry": "87600h"
    },
    "profiles": {
      "kubernetes": {
         "expiry": "87600h",
         "usages": [
            "signing",
            "key encipherment",
            "server auth",
            "client auth"
        ]
      }
    }
  }
}
EOF


cat << EOF | tee ca-csr.json
{
    "CN": "kubernetes",
    "key": {
        "algo": "rsa",
        "size": 2048
    },
    "names": [
        {
            "C": "CN",
            "L": "Beijing",
            "ST": "Beijing",
            "O": "k8s",
            "OU": "System"
        }
    ]
}
EOF

3.6 创建 kube-apiserver 证书申请文件

cat << EOF | tee server-csr.json
{
    "CN": "kubernetes",
    "hosts": [
      "10.0.0.1",
      "127.0.0.1",
      "192.168.1.134",
      "192.168.1.135",
      "192.168.1.136",
      "kubernetes",
      "kubernetes.default",
      "kubernetes.default.svc",
      "kubernetes.default.svc.cluster",
      "kubernetes.default.svc.cluster.local"
    ],
    "key": {
        "algo": "rsa",
        "size": 2048
    },
    "names": [
        {
            "C": "CN",
            "L": "Beijing",
            "ST": "Beijing",
            "O": "k8s",
            "OU": "System"
        }
    ]
}
EOF

3.7 生成 kube-apiserver HTTPS 证书

# 生成CA证书, 然后使用自签 CA 签发 kube-apiserver HTTPS 证书
cfssl gencert -initca ca-csr.json | cfssljson -bare ca -
cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=kubernetes server-csr.json | cfssljson -bare server
ls ca*pem && ls server*pem

4. 部署Etcd集群

4.1 下载安装包

cd ~/TLS/etcd
wget https://github.com/etcd-io/etcd/releases/download/v3.4.9/etcd-v3.4.9-linux-amd64.tar.gz
mkdir /opt/etcd/{bin,cfg,ssl} -p
tar zxvf etcd-v3.4.9-linux-amd64.tar.gz
mv etcd-v3.4.9-linux-amd64/{etcd,etcdctl} /opt/etcd/bin/

4.2 拷贝刚才生成的证书

cp ~/TLS/etcd/ca*pem ~/TLS/etcd/server*pem /opt/etcd/ssl/

4.3 创建 etcd配置文件

cat << EOF | tee /opt/etcd/cfg/etcd.conf
#[Member]
ETCD_NAME="etcd-1"
ETCD_DATA_DIR="/var/lib/etcd/default.etcd"
ETCD_LISTEN_PEER_URLS="https://192.168.1.134:2380"
ETCD_LISTEN_CLIENT_URLS="https://192.168.1.134:2379"

#[Clustering]
ETCD_INITIAL_ADVERTISE_PEER_URLS="https://192.168.1.134:2380"
ETCD_ADVERTISE_CLIENT_URLS="https://192.168.1.134:2379"
ETCD_INITIAL_CLUSTER="etcd-1=https://192.168.1.134:2380,etcd-2=https://192.168.1.135:2380,etcd-3=https://192.168.1.136:2380"
ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster"
ETCD_INITIAL_CLUSTER_STATE="new"
EOF

4.4 使用Systemd管理 etcd

cat << EOF |tee /usr/lib/systemd/system/etcd.service
[Unit]
Description=Etcd Server
After=network.target
After=network-online.target
Wants=network-online.target

[Service]
Type=notify
EnvironmentFile=/opt/etcd/cfg/etcd.conf
ExecStart=/opt/etcd/bin/etcd \
--cert-file=/opt/etcd/ssl/server.pem \
--key-file=/opt/etcd/ssl/server-key.pem \
--peer-cert-file=/opt/etcd/ssl/server.pem \
--peer-key-file=/opt/etcd/ssl/server-key.pem \
--trusted-ca-file=/opt/etcd/ssl/ca.pem \
--peer-trusted-ca-file=/opt/etcd/ssl/ca.pem \
--logger=zap
Restart=on-failure
LimitNOFILE=65536

[Install]
WantedBy=multi-user.target
EOF

4.5 拷贝文件到 Node 节点

# 注意复制过去后,修改下 etcd.conf 中IP地址,为节点的IP
scp -r /opt/etcd/ root@192.168.1.135:/opt/
scp -r /opt/etcd/ root@192.168.1.136:/opt/
scp /usr/lib/systemd/system/etcd.service root@192.168.1.135:/usr/lib/systemd/system/
scp /usr/lib/systemd/system/etcd.service root@192.168.1.136:/usr/lib/systemd/system/

4.6 启动 etcd

# 启动ETCD集群同时启动二个节点,单节点是无法正常启动的。
systemctl daemon-reload && systemctl start etcd && systemctl enable etcd

4.7 检查服务是否正常

ETCDCTL_API=3 /opt/etcd/bin/etcdctl --cacert=/opt/etcd/ssl/ca.pem --cert=/opt/etcd/ssl/server.pem --key=/opt/etcd/ssl/server-key.pem --endpoints="https://192.168.1.134:2379,https://192.168.1.135:2379,https://192.168.1.136:2379" endpoint health

https://192.168.1.134:2379 is healthy: successfully committed proposal: took = 9.978053ms
https://192.168.1.136:2379 is healthy: successfully committed proposal: took = 13.282176ms
https://192.168.1.135:2379 is healthy: successfully committed proposal: took = 12.787146ms
# 显示结果如上。如果不正常,查看日志: /var/log/message  或者 journalctl -u etcd

5. 安装 Docker

所有节点上

5.1 下载源码包

wget https://download.docker.com/linux/static/stable/x86_64/docker-19.03.9.tgz
tar zxvf docker-19.03.9.tgz 
mv docker/* /usr/bin

5.2 Systemd 管理 docker

cat <<EOF |tee /usr/lib/systemd/system/docker.service
[Unit] 
Description=Docker Application Container Engine 
Documentation=https://docs.docker.com 
After=network-online.target firewalld.service 
Wants=network-online.target 

[Service] 
Type=notify 
ExecStart=/usr/bin/dockerd 
ExecReload=/bin/kill -s HUP $MAINPID 
LimitNOFILE=infinity 
LimitNPROC=infinity 
LimitCORE=infinity 
TimeoutStartSec=0 
Delegate=yes 
KillMode=process 
Restart=on-failure 
StartLimitBurst=3 
StartLimitInterval=60s 

[Install] 
WantedBy=multi-user.target 
EOF

5.3 加速镜像

mkdir /etc/docker 
cat > /etc/docker/daemon.json << EOF 
{
	"registry-mirrors": ["https://b9pmyelo.mirror.aliyuncs.com"]
}
EOF

5.4 开机自启

systemctl daemon-reload && systemctl start docker && systemctl enable docker

6. 部署 Master Node

下载地址: https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG/CHANGELOG-1.18.md

这里使用版本: v1.18.3 , 下载 server 包,里面啥都有

安装 master 必须组件

6.1 下载二进制包

wget https://dl.k8s.io/v1.18.13/kubernetes-server-linux-amd64.tar.gz
mkdir -p /opt/kubernetes/{bin,cfg,ssl,logs}
tar zxvf kubernetes-server-linux-amd64.tar.gz
cd kubernetes/server/bin
cp kube-apiserver kube-scheduler kube-controller-manager /opt/kubernetes/bin
cp kubectl /usr/bin/
# 把刚才生成的证书拷贝到配置文件中的路径
cp ~/TLS/k8s/ca*pem ~/TLS/k8s/server*pem /opt/kubernetes/ssl/

6.2 启用 TLS Bootstrapping 机制

# token 生成  ====>  head -c 16 /dev/urandom | od -An -t x | tr -d ' '
# 格式:token,用户名,UID,用户组
cat > /opt/kubernetes/cfg/token.csv << EOF
c47ffb939f5ca36231d9e3121a252940,kubelet-bootstrap,10001,"system:node-bootstrapper"
EOF

6.3 部署 kube-apiserver

# kube-apiserver 配置文件
cat > /opt/kubernetes/cfg/kube-apiserver.conf << EOF
KUBE_APISERVER_OPTS="--logtostderr=false \\
--v=2 \\
--log-dir=/opt/kubernetes/logs \\
--etcd-servers=https://192.168.1.134:2379,https://192.168.1.135:2379,https://192.168.1.136:2379 \\
--bind-address=192.168.1.134 \\
--secure-port=6443 \\
--advertise-address=192.168.1.134 \\
--allow-privileged=true \\
--service-cluster-ip-range=10.0.0.0/24 \\
--enable-admission-plugins=NamespaceLifecycle,LimitRanger,ServiceAccount,ResourceQuota,NodeRestriction \\
--authorization-mode=RBAC,Node \\
--enable-bootstrap-token-auth=true \\
--token-auth-file=/opt/kubernetes/cfg/token.csv \\
--service-node-port-range=30000-32767 \\
--kubelet-client-certificate=/opt/kubernetes/ssl/server.pem \\
--kubelet-client-key=/opt/kubernetes/ssl/server-key.pem \\
--tls-cert-file=/opt/kubernetes/ssl/server.pem  \\
--tls-private-key-file=/opt/kubernetes/ssl/server-key.pem \\
--client-ca-file=/opt/kubernetes/ssl/ca.pem \\
--service-account-key-file=/opt/kubernetes/ssl/ca-key.pem \\
--etcd-cafile=/opt/etcd/ssl/ca.pem \\
--etcd-certfile=/opt/etcd/ssl/server.pem \\
--etcd-keyfile=/opt/etcd/ssl/server-key.pem \\
--audit-log-maxage=30 \\
--audit-log-maxbackup=3 \\
--audit-log-maxsize=100 \\
--audit-log-path=/opt/kubernetes/logs/k8s-audit.log"
EOF
# systemd 管理
cat > /usr/lib/systemd/system/kube-apiserver.service << EOF
[Unit]
Description=Kubernetes API Server
Documentation=https://github.com/kubernetes/kubernetes
[Service]
EnvironmentFile=/opt/kubernetes/cfg/kube-apiserver.conf
ExecStart=/opt/kubernetes/bin/kube-apiserver \$KUBE_APISERVER_OPTS
Restart=on-failure
[Install]
WantedBy=multi-user.target
EOF

systemctl daemon-reload && systemctl start kube-apiserver && systemctl enable kube-apiserver && systemctl status kube-apiserver
# 授权 kubelet-bootstrap 用户允许请求证书
kubectl create clusterrolebinding kubelet-bootstrap \
--clusterrole=system:node-bootstrapper \
--user=kubelet-bootstrap

参数详解: –logtostderr:启用日志 —v:日志等级 –log-dir:日志目录 –etcd-servers:etcd集群地址 –bind-address:监听地址 –secure-port:https安全端口 –advertise-address:集群通告地址 –allow-privileged:启用授权 –service-cluster-ip-range:Service虚拟IP地址段 –enable-admission-plugins:准入控制模块 –authorization-mode:认证授权,启用RBAC授权和节点自管理 –enable-bootstrap-token-auth:启用TLS bootstrap机制 –token-auth-file:bootstrap token文件 –service-node-port-range:Service nodeport类型默认分配端口范围 –kubelet-client-xxx:apiserver访问kubelet客户端证书 –tls-xxx-file:apiserver https证书 –etcd-xxxfile:连接Etcd集群证书 –audit-log-xxx:审计日志

6.4 部署kube-controller-manager

cat > /opt/kubernetes/cfg/kube-controller-manager.conf << EOF
KUBE_CONTROLLER_MANAGER_OPTS="--logtostderr=false \\
--v=2 \\
--log-dir=/opt/kubernetes/logs \\
--leader-elect=true \\
--master=127.0.0.1:8080 \\
--bind-address=127.0.0.1 \\
--allocate-node-cidrs=true \\
--cluster-cidr=10.244.0.0/16 \\
--service-cluster-ip-range=10.0.0.0/24 \\
--cluster-signing-cert-file=/opt/kubernetes/ssl/ca.pem \\
--cluster-signing-key-file=/opt/kubernetes/ssl/ca-key.pem  \\
--root-ca-file=/opt/kubernetes/ssl/ca.pem \\
--service-account-private-key-file=/opt/kubernetes/ssl/ca-key.pem \\
--experimental-cluster-signing-duration=87600h0m0s"
EOF


cat > /usr/lib/systemd/system/kube-controller-manager.service << EOF
[Unit]
Description=Kubernetes Controller Manager
Documentation=https://github.com/kubernetes/kubernetes
[Service]
EnvironmentFile=/opt/kubernetes/cfg/kube-controller-manager.conf
ExecStart=/opt/kubernetes/bin/kube-controller-manager \$KUBE_CONTROLLER_MANAGER_OPTS
Restart=on-failure
[Install]
WantedBy=multi-user.target
EOF



systemctl daemon-reload && systemctl start kube-controller-manager && systemctl enable kube-controller-manager && systemctl status kube-controller-manager

–master:通过本地非安全本地端口8080连接apiserver。 –leader-elect:当该组件启动多个时,自动选举(HA) –cluster-signing-cert-file/–cluster-signing-key-file:自动为kubelet颁发证书的CA,与apiserver保持一致

6.5 部署kube-scheduler

cat > /opt/kubernetes/cfg/kube-scheduler.conf << EOF
KUBE_SCHEDULER_OPTS="--logtostderr=false \
--v=2 \
--log-dir=/opt/kubernetes/logs \
--leader-elect \
--master=127.0.0.1:8080 \
--bind-address=127.0.0.1"
EOF



cat > /usr/lib/systemd/system/kube-scheduler.service << EOF
[Unit]
Description=Kubernetes Scheduler
Documentation=https://github.com/kubernetes/kubernetes
[Service]
EnvironmentFile=/opt/kubernetes/cfg/kube-scheduler.conf
ExecStart=/opt/kubernetes/bin/kube-scheduler \$KUBE_SCHEDULER_OPTS
Restart=on-failure
[Install]
WantedBy=multi-user.target
EOF


systemctl daemon-reload && systemctl start kube-scheduler && systemctl enable kube-scheduler && systemctl status kube-scheduler
#### 查看集群状态
[root@k8s-master ~]# kubectl get cs
NAME                 STATUS    MESSAGE             ERROR
scheduler            Healthy   ok                  
controller-manager   Healthy   ok                  
etcd-2               Healthy   {"health":"true"}   
etcd-0               Healthy   {"health":"true"}   
etcd-1               Healthy   {"health":"true"} 

7. 部署Worker Node

下面还是在 Master 上操作,即同时作为 Worker Node

7.1 创建工作目录并拷贝二进制文件

mkdir -p /opt/kubernetes/{bin,cfg,ssl,logs}
# 之前下载的 k8s server 包
cd kubernetes/server/bin
cp kubelet kube-proxy /opt/kubernetes/bin

7.2 部署 kubelet

# 1. 创建配置文件
cat > /opt/kubernetes/cfg/kubelet.conf << EOF
KUBELET_OPTS="--logtostderr=false \\
--v=2 \\
--log-dir=/opt/kubernetes/logs \\
--hostname-override=k8s-master \\
--network-plugin=cni \\
--kubeconfig=/opt/kubernetes/cfg/kubelet.kubeconfig \\
--bootstrap-kubeconfig=/opt/kubernetes/cfg/bootstrap.kubeconfig \\
--config=/opt/kubernetes/cfg/kubelet-config.yml \\
--cert-dir=/opt/kubernetes/ssl \\
--pod-infra-container-image=lizhenliang/pause-amd64:3.0"
EOF

# 2. 设置配置参数文件
cat > /opt/kubernetes/cfg/kubelet-config.yml << EOF
kind: KubeletConfiguration
apiVersion: kubelet.config.k8s.io/v1beta1
address: 0.0.0.0
port: 10250
readOnlyPort: 10255
cgroupDriver: cgroupfs
clusterDNS:
- 10.0.0.2
clusterDomain: cluster.local 
failSwapOn: false
authentication:
  anonymous:
    enabled: false
  webhook:
    cacheTTL: 2m0s
    enabled: true
  x509:
    clientCAFile: /opt/kubernetes/ssl/ca.pem 
authorization:
  mode: Webhook
  webhook:
    cacheAuthorizedTTL: 5m0s
    cacheUnauthorizedTTL: 30s
evictionHard:
  imagefs.available: 15%
  memory.available: 100Mi
  nodefs.available: 10%
  nodefs.inodesFree: 5%
maxOpenFiles: 1000000
maxPods: 110
EOF


# 3. 生成bootstrap.kubeconfig文件
KUBE_APISERVER="https://192.168.1.134:6443"
TOKEN="c47ffb939f5ca36231d9e3121a252940"

kubectl config set-cluster kubernetes \
  --certificate-authority=/opt/kubernetes/ssl/ca.pem \
  --embed-certs=true \
  --server=${KUBE_APISERVER} \
  --kubeconfig=bootstrap.kubeconfig
kubectl config set-credentials "kubelet-bootstrap" \
  --token=${TOKEN} \
  --kubeconfig=bootstrap.kubeconfig
kubectl config set-context default \
  --cluster=kubernetes \
  --user="kubelet-bootstrap" \
  --kubeconfig=bootstrap.kubeconfig
kubectl config use-context default --kubeconfig=bootstrap.kubeconfig

# 4. 拷贝到配置文件路径
cp bootstrap.kubeconfig /opt/kubernetes/cfg
cat > /usr/lib/systemd/system/kubelet.service << EOF
[Unit]
Description=Kubernetes Kubelet
After=docker.service
[Service]
EnvironmentFile=/opt/kubernetes/cfg/kubelet.conf
ExecStart=/opt/kubernetes/bin/kubelet \$KUBELET_OPTS
Restart=on-failure
LimitNOFILE=65536
[Install]
WantedBy=multi-user.target
EOF

systemctl daemon-reload && systemctl start kubelet && systemctl enable kubelet && systemctl status kubelet
# 查看kubelet证书请求
kubectl get csr
NAME                                                   AGE    SIGNERNAME                                    REQUESTOR           CONDITION
node-csr-uCEGPOIiDdlLODKts8J658HrFq9CZ--K6M4G7bjhk8A   6m3s   kubernetes.io/kube-apiserver-client-kubelet   kubelet-bootstrap   Pending

# 批准申请
kubectl certificate approve node-csr-uCEGPOIiDdlLODKts8J658HrFq9CZ--K6M4G7bjhk8A

# 查看节点
kubectl get node
NAME         STATUS     ROLES    AGE   VERSION
k8s-master   NotReady   <none>   7s    v1.18.3     # 注:由于网络插件还没有部署,节点会没有准备就绪 NotReady

7.3 部署kube-proxy

# 1. 创建配置文件
cat > /opt/kubernetes/cfg/kube-proxy.conf << EOF
KUBE_PROXY_OPTS="--logtostderr=false \\
--v=2 \\
--log-dir=/opt/kubernetes/logs \\
--config=/opt/kubernetes/cfg/kube-proxy-config.yml"
EOF

# 2. 配置文件参数
cat > /opt/kubernetes/cfg/kube-proxy-config.yml << EOF
kind: KubeProxyConfiguration
apiVersion: kubeproxy.config.k8s.io/v1alpha1
bindAddress: 0.0.0.0
metricsBindAddress: 0.0.0.0:10249
clientConnection:
  kubeconfig: /opt/kubernetes/cfg/kube-proxy.kubeconfig
hostnameOverride: k8s-master
clusterCIDR: 10.0.0.0/24
EOF

# 3. 创建证书请求文件
cd ~/TLS/k8s
cat > kube-proxy-csr.json << EOF
{
  "CN": "system:kube-proxy",
  "hosts": [],
  "key": {
    "algo": "rsa",
    "size": 2048
  },
  "names": [
    {
      "C": "CN",
      "L": "BeiJing",
      "ST": "BeiJing",
      "O": "k8s",
      "OU": "System"
    }
  ]
}
EOF

# 4. 生成证书
cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=kubernetes kube-proxy-csr.json | cfssljson -bare kube-proxy
ls kube-proxy*pem


# 5. 生成kube-proxy.kubeconfig文件
KUBE_APISERVER="https://192.168.1.134:6443"

kubectl config set-cluster kubernetes \
  --certificate-authority=/opt/kubernetes/ssl/ca.pem \
  --embed-certs=true \
  --server=${KUBE_APISERVER} \
  --kubeconfig=kube-proxy.kubeconfig
kubectl config set-credentials kube-proxy \
  --client-certificate=./kube-proxy.pem \
  --client-key=./kube-proxy-key.pem \
  --embed-certs=true \
  --kubeconfig=kube-proxy.kubeconfig
kubectl config set-context default \
  --cluster=kubernetes \
  --user=kube-proxy \
  --kubeconfig=kube-proxy.kubeconfig
kubectl config use-context default --kubeconfig=kube-proxy.kubeconfig

# 6. 拷贝到配置文件指定路径
cp kube-proxy.kubeconfig /opt/kubernetes/cfg/
cat > /usr/lib/systemd/system/kube-proxy.service << EOF
[Unit]
Description=Kubernetes Proxy
After=network.target
[Service]
EnvironmentFile=/opt/kubernetes/cfg/kube-proxy.conf
ExecStart=/opt/kubernetes/bin/kube-proxy \$KUBE_PROXY_OPTS
Restart=on-failure
LimitNOFILE=65536
[Install]
WantedBy=multi-user.target
EOF

systemctl daemon-reload && systemctl start kube-proxy && systemctl enable kube-proxy && systemctl status kube-proxy

7.4 部署CNI网络

部署

# 必须是 /opt/cni/bin 路径,不然 node 不是 Ready , https://github.com/containernetworking/plugins/releases/download/v0.8.6/cni-plugins-linux-amd64-v0.8.6.tgz
mkdir /opt/cni/bin -p
tar zxvf cni-plugins-linux-amd64-v0.8.6.tgz -C /opt/cni/bin
# flannel 地址:https://github.com/flannel-io/flannel
kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml

# 查看是否在安装
kubectl get pods -n kube-system
NAME                          READY   STATUS    RESTARTS   AGE
kube-flannel-ds-amd64-2pc95   1/1     Running   0          72s

# 查看是否已经准备就绪
kubectl get node
NAME         STATUS   ROLES    AGE   VERSION
k8s-master   Ready    <none>   41m   v1.18.3

授权 apiserver 访问 kubelet

cat > apiserver-to-kubelet-rbac.yaml << EOF
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  annotations:
    rbac.authorization.kubernetes.io/autoupdate: "true"
  labels:
    kubernetes.io/bootstrapping: rbac-defaults
  name: system:kube-apiserver-to-kubelet
rules:
  - apiGroups:
      - ""
    resources:
      - nodes/proxy
      - nodes/stats
      - nodes/log
      - nodes/spec
      - nodes/metrics
      - pods/log
    verbs:
      - "*"
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: system:kube-apiserver
  namespace: ""
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: system:kube-apiserver-to-kubelet
subjects:
  - apiGroup: rbac.authorization.k8s.io
    kind: User
    name: kubernetes
EOF

7.5 增加Worker Node

# 1. 在 master 节点将 Worker Node 涉及文件拷贝到新节点
scp -r /opt/kubernetes root@192.168.1.135:/opt/
scp -r /opt/kubernetes root@192.168.1.136:/opt/

scp -r /usr/lib/systemd/system/{kubelet,kube-proxy}.service root@192.168.1.135:/usr/lib/systemd/system
scp -r /usr/lib/systemd/system/{kubelet,kube-proxy}.service root@192.168.1.136:/usr/lib/systemd/system

scp -r /opt/cni/ root@192.168.1.135:/opt/
scp -r /opt/cni/ root@192.168.1.136:/opt/


scp /opt/kubernetes/ssl/ca.pem root@192.168.1.135:/opt/kubernetes/ssl
scp /opt/kubernetes/ssl/ca.pem root@192.168.1.136:/opt/kubernetes/ssl

# 2. 在新节点上删除kubelet证书和kubeconfig文件;  注:这几个文件是证书申请审批后自动生成的,每个Node不同,必须删除重新生成。
rm -f /opt/kubernetes/cfg/kubelet.kubeconfig 
rm -f /opt/kubernetes/ssl/kubelet*

# 3. 在新节点上修改主机名;  kebelet、 kube-proxy
vi /opt/kubernetes/cfg/kubelet.conf
--hostname-override=k8s-node01

vi /opt/kubernetes/cfg/kube-proxy-config.yml
hostnameOverride: k8s-node01

# 4. 在新节点上启动并设置开机启动
systemctl daemon-reload
systemctl start kubelet kube-proxy
systemctl enable kubelet kube-proxy
systemctl status kubelet kube-proxy

# 5. 回到 Master 上批准新Node kubelet证书申请
kubectl get csr
NAME                                                   AGE   SIGNERNAME                                    REQUESTOR           CONDITION
node-csr-4zTjsaVSrhuyhIGqsefxzVoZDCNKei-aE2jyTP81Uro   89s   kubernetes.io/kube-apiserver-client-kubelet   kubelet-bootstrap   Pending

kubectl certificate approve node-csr-4zTjsaVSrhuyhIGqsefxzVoZDCNKei-aE2jyTP81Uro

# 6. 查看Node状态
kubectl get node

第三部分 K8S核心技术

  • Pod

  • 控制器

  • 储存

  • Sservice

  • 调度器

  • 安全机制RBAC

  • 包管理工具 Helm等等

1. Pod

1.1 Pod 基本概念

  • 最小部署单元

  • 包含多个容器(一组容器的集合)

  • 一个pod中容器共享网络命名空间

  • pod是短暂的

1.2 Pod 实现机制

  • 共享网络: 通过Pause容器,把其他业务容器加入到Pansu容器里,让所有业务容器在同一个命名空间中,实现网络共享

  • 共享存储: 引入数据卷 Volumn,使用数据卷进行持久化存储

Pod 特性
说明

资源共享

一个pod中多个容器共享存储和网络

生命周期短暂

若Pod节点发生故障,那么该Pod会调度到其他节点,是一个全新的Pod,跟之前的pod无关联

平坦的网络

所有Pod都在同一共享网络地址空间中,每个Pod可以通过其他Pod的IP进行访问

1.3 Pod 生命周期和重启策略

Pod 状态
说明

Pending

API Server已经创建该Pod,但Pod中的一个或多个容器还没创建,包括镜像下载过程

Running

Pod内错有容器已创建,且至少一个容器处于运行状态、正在启动或正在重启

Completed

Pod内所有容器均成功执行退出,且不会重启

Faild

Pod内所有容器均已退出,但至少一个容器退出失败

Unknow

由于某种原因无法获取Pod状态,例如网络通信不畅

Pod 重启策略
说明

Always

当容器失效时,由kubelet自动重启该容器

OnFailure

当容器终止运行且退出码不为0,由kubelet自动重启该容器

Never

不论容器运行状态如何, kublete都不会重启该容器

Pod包含的容器数
Pod当前的状态
发生事件
Pod的结果状态

RestartPolicy=Always

RestartPolicy=OnFailure

RestartPolicy=Never

包含一个容器

Running

容器成功退出

Running

Successded

Successded

包含一个容器

Running

容器失败退出

Running

Running

Failure

包含两个容器

Running

1个容器失败退出

Running

Running

Running

包含两个容器

Running

容器被OOM杀掉

Running

Running

Failure

1.4 Pod 资源配置

  • requests:需求,最低保障;

  • limits:限制,硬限制; 超过被杀死

apiVersion: v1
kind: Pod
metadata:
  name: pod-demo
  labels:
    app: myapp
spec:
  containers:
  - name: myapp
    image: nginx
    resources:
      requests:
        cpu: "200m"
        memory: "128Mi"
      limits:
        cpu: "500m"
        memory: "512Mi"
# 上述代码表明 Nginx 容器申请最少 0.2 个 CPU 以及 128MiB 内存,在运行过程中容器所能使 用的资源配额为 0.5 个 CPU 以及 512MiB 内存。

1.5 Pod 健康检查

  • livenessProbe (存活检查)

    如果检查失败,将杀死容器,根据Pod的 restartPolicy 来操作

  • readlinessProbe (就绪检查)

    如果检查失败, Kubernetes会把Pod从 service endpoint中剔除

Probe 支持是三种检查方式
说明

httpget

发送HTTP请求,返回200·400范围状态码为成功

exec

执行Shell命令返回状态码是0为成功

tcpSocket

发起 Tcp Socket 建立成功

1.6 Pod 创建流程

​ - 1、 kubect 向 Apiserver 发送创建Pod请求 ​ - 2、Api server 收到请求,生成 YAML 文件,并把YAML信息写入 Etcd 中 ​ - 3、 Scheduler 调度器通过Apiserver 读取 Etcd 信息进行判断,如果是NUll,使用调度算法,分配到资源利用少的节点上,并把更新信息写入 Etcd内, ​ - 4、Node 节点上 的 kubelet 会不停的请求 apiserver,读取Etcd数据,如果编号和自己的相同,则调用 dcokerApi,创建容器

1.7 Pod 调度(节点亲和)

​ - 硬亲和性: 约束条件必须满足 ​ - 软亲和性: 尝试满足,不保证

支持常用操作符: In NotIn Exists Gt Lt DoesNotExists

  • 影响调度的属性

    • Pod 资源限制对Pod调用产生影响 ( 设置资源限制过大,会找不到足够资源的node节点)

    • 节点选择器标签影响 Pod 调度 (只可调用到指定标签的节点)

1.8 Pod 调度(节点污点)

  • 使用场景

    • 专用节点

    • 配置特点、硬件特点

    • 基于 Taint 驱逐

  • 污点值 <常用于master节点> - Noschedule 一定不被调度 - PreferNoSchedule 尽量不被调度 - NoExecute 不会调度,并且驱逐已有的 Pod

#  查看污点
kubectl describe node <节点名字> |grep -i taint
# 为节点添加污点
kubectl taint node <节点名称> key=value:<污点值>
# 删除污点,注意后面要加  - 
kubectl taint node <节点名称> key=value:<污点值>-
  • 污点容忍

    比如某个节点节点被标记为了污点节点,要想 pod 能够调度到 master 节点去,这个该怎么办?```

tolerations:
- key: "key"
  operator: "Exists"
  value: 'Equal'
  effect: "NoSchedule"
# 或者
tolerations:
- key: "key"
  operator: "Exists"
  effect: "NoSchedule"
  
# 如果 operator 的值是 Exists,则 value 属性可省略
# 如果 operator 的值是 Equal,则表示其 key 与 value 之间的关系是 equal(等于)
# 如果不指定 operator 属性,则默认值为 Equal

2. Controller

2.1 什么是 Controller?

在集群上管理和运行容器的对象,俗称控制器

2.2 Pod 与 Controller 关系?

Pod 是通过 Controller 实现应用的运维,比如伸缩、滚动升级等等

2.3 Deployment 控制器应用场景

  • 部署无状态应用

  • 管理 Pod 与 ReplicaSet

  • 部署,滚动升级等功能

    ------- 主要应用场景: web服务、微服务

2.4 Yaml 文件字段说明

# 使用 deployment 部署应用(上下选择标签要相同)
··· 
spec:
  replicas: 1
  selector:
    matchLabels:
      app: web
  template:
    metadata:
      labels:
        app: web

2.5 Deployment 控制器部署应用

# 1. 导出 Yaml 文件 <主要是为了后面重新生成>
kubectl create deploy web --image=nginx --dry-run=client -o yaml > web.yaml
# 2. 部署应用
kubectl apply -f web.yaml
# 3. 对外发布 (暴露对外端口号,这种方法,一个端口只能用于这一个应用)
kubectl expose deploy web --port=80 --target-port=80 --type=NodePort --name=web1 -o yaml > web1.yaml
kubectl apply -f web1.yaml
kubectl get svc    ----> web1         NodePort    10.0.0.202   <none>        80:31281/TCP   2m56s
# 测试端口访问
curl localhost:31281

2.6 应用升级回滚和弹性伸缩

# 应用升级版本
kubectl set image deploy web nginx=nginx:1.15
# 查看升级的状态
kubectl rollout status deploy web
# 查看升级的版本
kubectl rollout history deploy web


# 新版本不好用,再切回来老版本;回滚
kubectl rollout undo deploy web

# 回滚到指定的版本
kubectl rollout undo deploy web --to-revision=2


# 手动弹性伸缩
kubectl scale deploy web --replicas=5

3. Service

 服务发现

3.1 Service 存在意义

  • 防止与 Pod 的是失联

  • 定义一组Pod 的访问策略 (相当于负载均衡器)

3.2 Service 和 Pod 关系

​ - Pod 类似架构中的 后端服务器, Service 相当于架构中的虚拟 VIP,通过Service实现负载均衡

​ - Pod 与 Service 根据 Label 和 selector 标签选择器建立关联

3.3 Servier 类型

  • 1、ClusterIP: 集群内部使用

  • 2、NodePort: 对外访问应用

  • 3、LoadBalancor: 对外访问应用使用,公有云

4. 无状态和有状态

4-1 无状态

  • 认为Pod 都是一样的

  • 没有顺序要求

  • 不用考虑在哪个 node 运行

  • 随意进行伸缩和扩展

4-2 有状态

  • 用于无状态的特点

  • 会让每个Pod独立,保持 Pod 启动顺序和唯一性

  • 唯一的网络标识符,持久存储

  • 有序,比如mysql主从

4-3 部署有状态应用

  • 无头Service

    ClusterIP: none # 通过YAML文件设置 ClusterIP 为 None

  • SatefulSet 部署有状态应用

    kind: StatefulSet # 通过YAML文件设置 kind 为 StatefulSet

    - 能保证每个 Pod 名称唯一性

注意: deployment 和 SatefulSet 区别:<唯一标识不同>

deployment : 根据主机名 + 安装一定规则生成域名 SatefulSet: 根据主机名称.service名称.名称空间.svc.cluster.local

3.4-4 DaemonSet 守护进程

  • 在每个node上运行一个pod, 新加入的 node 也同样运行这个pod

  • 例如: 在每个 node 节点上安装数据采集工具

5 计划任务

5.1 一次性任务

apiVersion: batch/v1
kind: Job
metadata:
  name: myjob
spec:
  # 同时启动两个任务
  #parallelism: 2  
  template:
    metadata:
      name: myjb
    spec:
      containers:
      - name: hello
        image: busybox
        command: ["echo","hello k8s job"]
      restartPolicy: Never
      
# 常用命令
kubectl get jobs
kubectl delete jobs xxx

5.2 定时任务

apiVersion: batch/v1beta1
kind: CronJob
metadata:
  name: mycronjob
spec:
  schedule: "*/1 * * * *"
  jobTemplate:
    spec:
      template:
        metadata:
          name: mycronjob
        spec:
          containers:
          - name: hello
            image: busybox
            command: ["echo","hello k8s job"]
          restartPolicy: OnFailure
          
# 常用命令
kubectl get cronjob
kubectl delete cronjob  xxx

6. Secret

6.1 Secret存在意义

Secret 解决了密码、token、密钥等敏感数据的配置问题,而不需要把这些敏感数据暴露 到镜像或者 Pod Spec 中。Secret 可以以 Volume 或者环境变量的方式使用

作用: 加密数据存在 etcd 里面, 让 Pod 容器以挂载 Volume 方式镜像访问

场景: 凭证

6.2 Secret 有三种类型

  • Service Account :用来访问 Kubernetes API,由 Kubernetes 自动创建,并且会自动挂载到Pod 的 /run/secrets/kubernetes.io/serviceaccount 目录中

  • Opaque : base64 编码格式的 Secret,用来存储密码、密钥等

  • kubernetes.io/dockerconfigjson :用来存储私有 docker registry 的认证信息

6.2-1 Service Account

kubectl run nginx --image nginx
kubectl exec nginx ls /var/run/secrets/kubernetes.io/serviceaccount
> ca.crt  namespace  token

6.2-2 Opaque Secret

1. 编写一个 secret 对象

echo -n "admin" | base64           ---> YWRtaW4=
echo -n "1f2d1e2e67df" | base64    ---> MWYyZDFlMmU2N2Rm:

# cat secrets.yaml
apiVersion: v1 
kind: Secret 
metadata: 
  name: mysecret 
type: Opaque 
data: 
  password: MWYyZDFlMmU2N2Rm 
  username: YWRtaW4=
  
kubectl apply -f secrets.yaml
kubectl get secret
> mysecret              Opaque                                2      32s

2. 将 Secret 挂载到Volume中

# cat pod1.yml 
apiVersion: v1
kind: Pod
metadata:
  name: mysecret
spec:
  containers:
  - name: demo
    image: myapp:v1
    volumeMounts:
    - name: secrets
      mountPath: "/secret"
      readOnly: true
  volumes:
  - name: secrets
    secret:
      secretName: mysecret
      #items:       向指定路径映射 secret 密钥
      #- key: username
      #  path: my-group/my-username  #相对路径
      
kubectl apply -f pod1.yml
kubectl exec mysecret --  ls /secret

3. 将 Secret 设置为环境变量

 缺点: 环境变量读取 Secret 很方便,但无法支撑Secret动态更新。

# cat pod2.yml 
apiVersion: v1
kind: Pod
metadata:
  name: secret-env
spec:
  containers:
  - name: nginx
    image: myapp:v1
    env:
      - name: SECRET_USERNAME
        valueFrom:
          secretKeyRef:
            name: mysecret
            key: username
      - name: SECRET_PASSWORD
        valueFrom:
          secretKeyRef:
            name: mysecret
            key: password

kubectl apply -f pods.yml
kubectl exec secret-env -- env
> SECRET_USERNAME=admin
> SECRET_PASSWORD=1f2d1e2e67df

6.2-3 dockerconfigjson

kubernetes.io/dockerconfigjson 用于存储 docker registry 的认证信息.

# 使用 Kuberctl 创建 docker registry 认证的 secret
kubectl create secret docker-registry myregistrykey --docker- server=DOCKER_REGISTRY_SERVER -- docker-username=DOCKER_USER --docker- password=DOCKER_PASSWORD --docker-email=DOCKER_EMAIL
> secret "myregistrykey" created.

# cat pod3.yml  在创建 Pod 的时候,通过 imagePullSecrets 来引用刚创建的'myregistrykey
apiVersion: v1
kind: Pod
metadata:
  name: mypod
spec:
  containers:
    - name: mario
      image: reg.westos.org/westos/mario
  imagePullSecrets:
    - name: myregistrykey    ##没有则无法访问私有仓库

6.3 ConfigMap

作用: 存储不加密数据到 etcd, 让Pod以变量或者Volume挂载到容器中 场景: 配置文件

6.3-1 Pod 使用 ConfigMap 方式?

  • 将ConfigMap中的数据设置为环境变量

  • 将ConfigMap中的数据设置为命令行参数

  • 使用Volume将ConfigMap作为文件或目录挂载

注意: - ConfigMap必须在Pod使用它之前创建 - 使用envFrom时,将会自动忽略无效的键 - Pod只能使用同一个命名空间的ConfigMap

6.3-2 创建ConfigMap两种方式

方式(1):命令行方式

kubectl create configmap nginxconfig --from-file /server/yaml/nginx/nginx.conf #通过命令直接创建
kubectl get configmap nginxconfig -o yaml #查看文件

方式(2):YMAL文件方式

cat nginx-configmap.yaml 
#-----------------------------创建命名空间----------------------------
apiVersion: v1
kind: Namespace                 
metadata:
  name: mt-math                  #创建的命名空间名称为mt-math
---
#-----------------------------创建configmap文件-----------------------
#创建configmap有多种方式,可以通过命令如:
#kubectl create configmap nginxconfig --from-file /server/yaml/nginx/nginx.conf
#查看创建的yaml文件内容:kubectl get configmap nginxconfig -o yaml
#这里采用标准的yaml文件格式进行创建:更新时采用:kubectl  replace -f nginx-configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: nginxconfig
  namespace: mt-math
data:
  nginx.conf: |
    #########wyl530
    user nginx;
    worker_processes auto;
    error_log /etc/nginx/error.log;
    pid /run/nginx.pid;
    include /usr/share/nginx/modules/*.conf;
    events {
        worker_connections 1024;
    }
    http {
        log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                          '$status $body_bytes_sent "$http_referer" '
                          '"$http_user_agent" "$http_x_forwarded_for"';
        server_tokens     off;
        access_log        /usr/share/nginx/html/access.log  main;
        sendfile            on;
        tcp_nopush          on;
        tcp_nodelay         on;
        keepalive_timeout   65;
        types_hash_max_size 2048;
        include             /etc/nginx/mime.types;
        default_type        application/octet-stream;
        include /etc/nginx/conf.d/*.conf;
        server {
            listen       80 default_server;
            listen       [::]:80 default_server;
            server_name  _;
            root         /usr/share/nginx/html;
            include /etc/nginx/default.d/*.conf;
            location / {
            }
            error_page 404 /404.html;
                location = /40x.html {
            }
            error_page 500 502 503 504 /50x.html;
                location = /50x.html {
            }
        }

    }

创建pod yaml文件

cat deployment.yaml 
#----------------------------创建pv---------------------------------
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv-nfs-pv01             #创建的pv名称可创建多个.
  namespace: mt-math            #属于的命名空间
  labels:
    pv: pv-nfs-01               #定义pv标签,后续通过pvc绑定特定的pv标签。通常如果不写标签则默认通过访问方式和storage大小进行批量绑定。(重要)
spec:
  capacity:
    storage: 1Gi                 #创建的pv-nfs-pv01大小为1G
  accessModes:
  - ReadWriteMany
  nfs:                           #创建的pv数据来源
    path: /NFS/pv01              #数据源目录
    server: 192.168.0.14         #数据源ip
#--------------------------------创建pvc--------------------------------
---
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: nfs-data-pvc              #创建的pvc名称
  namespace: mt-math              #属于的命名空间 
spec:
  accessModes:
    - ReadWriteMany                       
  resources:
    requests:
      storage: 1Gi               #请求大小为1G
  selector:                      #定义标签选择器,此时k8s会根据标签,storage,访问方式 进行匹配。三者同时满足才会绑定。如果不定义,则系统会根据storage的大小和访问方式进行匹配绑定.
    matchLabels:
      pv: pv-nfs-01              #定义请求标签为pv-nfs-pv01的pv且大小为1G
#--------------------------------创建pod------------------------------------
---
apiVersion: extensions/v1beta1   #接口版本
kind: Deployment                 #接口类型
metadata:                        #基础标签名称信息
  name: wyl-nginx                #创建的pod名称
  namespace: mt-math             #创建的pod属于mt-math命名空间
spec:                            #详细参数设置
  replicas: 3                    #副本数量
  selector:                      #标签选择器
    matchLabels:
      app: wyl-nginx             #正对标签为wyl-nginx的pod进行副本的创建
  strategy:
    rollingUpdate:               #由于replicas为3,则整个升级,pod个数在2-4个之间
      maxSurge: 1                #滚动升级时会先启动1个pod
      maxUnavailable: 1          #滚动升级时允许的最大Unavailable的pod个数
  template:                      #模板
    metadata:
      labels:
        app: wyl-nginx           #模板pod名称必填
    spec:                        #定义容器模板信息,该模板可以包含多个容器
      containers:
        - name:  nginx
          image: nginx:latest
          imagePullPolicy: IfNotPresent
          ports:
            - name: http
              containerPort: 80
          volumeMounts:
          - name: nginx-nfs
            mountPath: /usr/share/nginx/html
          - name: nginx-pvc
            mountPath: /var/log/nginx
            subPath: nginx.conf
          - name: nginx-etc       #挂载数据节点名称
            mountPath: /etc/nginx/nginx.conf #挂载此目录
            subPath: nginx.conf
      volumes:                    #设置挂载
      - name: nginx-nfs           #挂载的数据节点名称
        nfs:                      #挂载的服务类型
          server: 192.168.0.14    #服务Ip
          path: /NFS/wwwroot      #挂载数据目录
      - name: nginx-pvc           #挂载数据节点名称
        persistentVolumeClaim:    #服务类型
          claimName: nfs-data-pvc #数据源名称
      - name: nginx-etc           #挂载数据节点名称
        configMap:
         name: nginxconfig        #指定创建configMap的名称
         items:
          - key: nginx.conf       #key为文件名称
            path: nginx.conf      #文件路径内容
---
#-----------------------创建server-------------------------------------------
kind: Service
apiVersion: v1
metadata:
  name: wyl-nginx             
  namespace: mt-math             #属于的命名空间
spec:
  selector:
    app: wyl-nginx               #针对标签为wyl-nginx的标签进行负载
  type: NodePort                 #正对Node节点进行端口暴露
  ports:                       
    - protocol: TCP              #使用端口的协议
      port: 3017                 #供内网访问暴露的端口
      targetPort: 80             #目标pod的端口
      nodePort: 33333            #node节点暴露的端口
#简单说明-------------------------------------------------------------------
#1.创建了mt-math命名空间,删除命名空间默认删除该命名空间下的所有资源服务
#2.创建了pv,pv不属于任何命名空间
#3.创建了pvc,pvc属于mt-math命名空间
#4.创建了pod属于mt-math命名空间
#5.创建了server属于mt-math命名空间
#6.建议将pv单独写到一个文件中.否则在我们删除改命名空间下的所有服务后,利用该文件再次创建时会报pv已经创建.
#---------------------------------------------------------------------------

创建资源服务

kubectl create -f /server/yaml/nginx/nginx-configmap.yaml 
kubectl create -f /server/yaml/nginx/deployment.yaml 
kubectl exec -it wyl-nginx-d6f68d775-l4rkb --namespace=mt-math -- cat /etc/nginx/nginx.conf |head -1

7. 集群安全机制

7.1 概述

RBAC 实现机制:基于角色的访问控制

大白话: 白名单机制,想让他具备什么权限,就先创建某个角色Role,然后定制rules,再将某个用户user与role绑定,bind得到这种绑定关系为RoleBind

- Role 权限的集合 - ClusterRole 集群角色 - RoleBinding 角色绑定 - ClusterRoleBinding 集群角色绑定

8. helm

8.1 Helm 安装<包管理工具>

  • helm:一个命令行客户端工具,主要用于 Kubernetes 应用 chart 的创建、打包、发 布和管理。

  • Chart:应用描述,一系列用于描述 k8s 资源相关文件的集合。

  • Release:基于 Chart 的部署实体,一个 chart 被 Helm 运行后将会生成对应的一个 release;将在 k8s 中创建出真实运行的资源对象。

# Helm 客户端下载地址:https://github.com/helm/helm/releases
wget https://get.helm.sh/helm-v3.2.1-linux-amd64.tar.gz
tar fx helm-v3.2.1-linux-amd64.tar.gz
mv linux-amd64/helm /usr/bin/

# 添加存储库
helm repo add stable http://mirror.azure.cn/kubernetes/charts 
helm repo add aliyun https://kubernetes.oss-cn-hangzhou.aliyuncs.com/charts 
helm repo update

# 查看配置的存储库
helm repo list 
helm search repo stable


# 删除某个存储库,比如aliyun
helm repo remove aliyun

helm 配置国内 chart 仓库 微软仓库: http://mirror.azure.cn/kubernetes/charts 阿里云仓库: https://kubernetes.oss-cn-hangzhou.aliyuncs.com/charts 官方仓库: https://hub.kubeapps.com/charts/incubator

命令
描述

create

创建一个chart 并指定名字

dependency

管理 chart 依赖

get

下载一个release.可用子命令: all 、hooks、manifest、notes、values

history

获取 release 历史

install

安装一个 chart

list

列出 release

package

将 chart 目录打包到 chart 存档文件中

pull

从远程仓库下载 chart 并解压到本地

repo

添加,列出,移除,更新和索引chart仓库:可用子命令add, index, list, remove, update

rollback

从之前版本回滚

search

根据关键字搜索chart。可用子命令: all, repo

show

查看chart想想信息,可用子命令:all,chart,readme,values

status

显示已命名版本的状态

template

本地呈现摸版

uninstall

卸载一个 release

upgrade

更新一个 release

version

查看helm客户端版本

8.2 使用 chart 部署一个应用

helm search repo weave
helm install ui stable/weave-scope
helm list
# 源码安装: 提示错误: Error: Kubernetes cluster unreachable
# export KUBERNETES_MASTER=http://127.0.0.1:8080  只需要指定一下apiserver的地址和端口号即可 
# 修改 service Type: NodePort 即可访问 ui

9. Ingress

9.1 概述

在Kubernetes中,服务和Pod的IP地址仅可以在集群网络内部使用,对于集群外的应用是不可见的。为了使外部的应用能够访问集群内的服务,在Kubernetes 目前 提供了以下几种方案:
 - NodePort
 - LoadBalancer
 - Ingress
 
# 组成
ingress controller
  将新加入的Ingress转化成Nginx的配置文件并使之生效
ingress服务
  将Nginx的配置抽象成一个Ingress对象,每添加一个新的服务只需写一个新的Ingress的yaml文件即可

9.2 工作原理

1. ingress controller通过和kubernetes api交互,动态的去感知集群中ingress规则变化
2. 然后读取它,按照自定义的规则,规则里写明了哪个域名对应哪个service,生成一段nginx配置,
3. 再写到nginx-ingress-control的pod里,这个Ingress controller的pod里运行着一个Nginx服务,控制器会把生成的nginx配置写入/etc/nginx.conf文件中
4. 然后reload一下使配置生效。以此达到域名分配置和动态更新的问题。 

9.3 部署Ingress 两种方式

下载部署文件

# Github 地址: https://github.com/kubernetes/ingress-nginx
wget https://github.com/kubernetes/ingress-nginx/blob/nginx-0.30.0/deploy/static/mandatory.yaml

1.namespace.yaml 
创建一个独立的命名空间 ingress-nginx
2.configmap.yaml 
ConfigMap是存储通用的配置变量的,类似于配置文件,使用户可以将分布式系统中用于不同模块的环境变量统一到一个对象中管理;而它与配置文件的区别在于它是存在集群的“环境”中的,并且支持K8S集群中所有通用的操作调用方式。
从数据角度来看,ConfigMap的类型只是键值组,用于存储被Pod或者其他资源对象(如RC)访问的信息。这与secret的设计理念有异曲同工之妙,主要区别在于ConfigMap通常不用于存储敏感信息,而只存储简单的文本信息。
ConfigMap可以保存环境变量的属性,也可以保存配置文件。
创建pod时,对configmap进行绑定,pod内的应用可以直接引用ConfigMap的配置。相当于configmap为应用/运行环境封装配置。
pod使用ConfigMap,通常用于:设置环境变量的值、设置命令行参数、创建配置文件。

3.default-backend.yaml 
如果外界访问的域名不存在的话,则默认转发到default-http-backend这个Service,其会直接返回404:

4.rbac.yaml 
负责Ingress的RBAC授权的控制,其创建了Ingress用到的ServiceAccount、ClusterRole、Role、RoleBinding、ClusterRoleBinding

5.with-rbac.yaml 
是Ingress的核心,用于创建ingress-controller。前面提到过,ingress-controller的作用是将新加入的Ingress进行转化为Nginx的配置

方式一:Nodeport方式

mandatory.yaml 中的镜像可修改成国内镜像: 例如: - registry.cn-qingdao.aliyuncs.com/kubernetes_xingej/defaultbackend-amd64 - registry.cn-qingdao.aliyuncs.com/kubernetes_xingej/nginx-ingress-controller

# 下载yaml文件并更新mandatory.yaml中的镜像地址(master上)若国内服务器: 需替换下镜像地址
mkdir ingress-nginx && cd ingress-nginx
wget https://github.com/kubernetes/ingress-nginx/blob/nginx-0.30.0/deploy/static/mandatory.yaml
wget https://github.com/deploy/static/provider/baremetal/service-nodeport.yaml  # nodeport 方式需要额外使用这个文件

# 编辑 service-nodeport.yaml, 添加两行,分别在 http、https下,意思是暴露对外端口
nodePort: 32080  #http
nodePort: 32443  #https

# 运行部署上面两个文件
kubectl apply -f mandatory.yaml
kubectl apply -f service-nodeport.yaml

helm 创建工作环境

[root@k8s-master]# helm create mychart
[root@k8s-master]# rm -f mychart/templates/*
[root@k8s-master mychart]# tree
.
├── charts
├── Chart.yaml
├── templates
│   ├── deployment.yaml
│   ├── ingress.yaml
│   └── service.yaml
└── values.yaml  <暂没写变量,测试使用>

depoyment.yaml

### cat deployment.yaml
apiVersion: v1
kind: Namespace
metadata:
  name: mytest

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp
  namespace: mytest
  labels:
    app: myapp
spec:
  replicas: 1
  selector:
    matchLabels:
      app: myapp
  template:
    metadata:
      labels:
        app: myapp
    spec:
      containers:
        - name: myapp
          image: nginx
          ports:
            - containerPort: 80
              name: http
              protocol: TCP

service.yaml

# cat service.yaml
apiVersion: v1
kind: Service
metadata:
  name: myapp-svc
  namespace: mytest
spec:
  selector:
    app: myapp
  ports:
    - port: 80
      protocol: TCP
      targetPort: 80

Ingress.yaml

# cat ingress.yaml
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: myapp-ingress
  namespace: mytest
spec:
  rules:
    - host: myapp.com
      http:
        paths:
          - path: /
            backend:
              serviceName: myapp-svc
              servicePort: 80

helm 部署

helm install ./mychart --generate-name
访问: myapp.com:32080

方式二:deamonset方式

deamonset方式与nodeport方式只有一处不同,只修改mandatory.yaml,而且,service-nodeport.yaml也不用配置,其他不用修改,访问的时候,直接域名访问,不用加nodeport。

9. Yaml格式的pod定义文件完整内容

apiVersion: v1          #必选,版本号,例如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

10. NFS

10.1 服务端

yum -y install nfs-utils rpcbind
systemctl start rpcbind nfs
systemctl enable rpcbind nfs
rpcinfo -p localhost    # 查看nfs服务是否安装正常

# 比如我们在服务端的共享目录为/nfs-share,接着输入以下命令配置共享目录, 并使共享目录生效
echo "/nfs-share *(rw,async,no_root_squash)" >> /etc/exports
exportfs -r
systemctl restart rpcbind nfs

# 测试, 若不在一个VPC下,需开放: 111(TCP|UDP) 、20048(TCP|UDP) 、2049(TCP)
showmount -e localhost  或者  showmount -e 公网ip

10.2 客户端

yum install nfs-utils rpcbind -y
systemctl start rpcbind nfs
systemctl enable rpcbind nfs

# 命令挂载
mount -t nfs IP:/nfs-share /client-dir
# /etc/fstab
IP:/nfs-share      /client-dir       nfs     default 0       0

11. StorageClass

11.1 流程

  1. 创建一个可用的NFS Serve

  2. 创建Service Account.这是用来管控NFS provisioner在k8s集群中运行的权限

  3. 创建StorageClass.负责建立PVC并调用NFS provisioner进行预定的工作,并让PV与PVC建立管理

  4. 创建NFS provisioner.有两个功能,一个是在NFS共享目录下创建挂载点(volume),另一个则是建了PV并将PV与NFS的挂载点建立关联

11.2 访问模式和回收策略

  • 访问模式

    RWO  ReadWriteOnce -- 该volume只能被单个节点以读写的方式映射
    ROX  ReadOnlyMany -- 该volume可以被多个节点以只读方式映射
    RWX  ReadWriteMany -- 该volume可以被多个节点以读写的方式映射
  • 回收策略

    Retain:保留,需要手动回收 < 推荐这种模式 >
    Recycle:回收,自动删除卷中数据
    Delete:删除,相关联的存储资产,如AWS EBS,GCE PD,Azure Disk,or OpenStack Cinder卷都会被删除
  • 状态

    Available:  空闲的资源,未绑定给PVC
    Bound:      绑定给了某个PVC
    Released:   PVC已经删除了,但是PV还没有被集群回收
    Failed:     PV在自动回收中失败了
    命令行可以显示PV绑定的PVC名称。

11.3 NFS 静态方式 PV

集群管理员创建多个PV,它们携带着真实存储的详细信息,这些存储对于集群用户是可用的。它们存在于Kubernetes API中,并可用于存储使用。

# 环境: kubernetes 1.18.3, 例如文件: test.yaml
apiVersion: v1
kind: Namespace
metadata:
  name: mytest
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: nfs-pv                      # PV 不需要绑定名称空间
  labels:
    pv: nfs-pv
spec:
  capacity:
    storage: 1Gi
  volumeMode: Filesystem
  accessModes:
    - ReadWriteMany                # 访问模式
  persistentVolumeReclaimPolicy: Retain   # 回收策略
  storageClassName: nfs            # storageClassName 定义的名字,为了pvc匹配
  nfs:
    path: /nfs/data                # NFS 共享目录
    server: 192.168.1.33           # NFS 共享地址

---

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: nfs-pvc
  namespace: mytest
spec:
  storageClassName: nfs              # 对应上面创建 PV 的 storageClassName名字
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 1Gi


---
apiVersion: v1
kind: Pod
metadata:
  name: mypod
  namespace: mytest
spec:
  containers:
    - name: nginx
      image: nginx
      volumeMounts:
      - mountPath: /usr/share/nginx/html
        name: nfs-pv                        # 对应上面创建 PV 的名字
  volumes:
    - name: nfs-pv                          # 对应上面创建 PV 的名字
      persistentVolumeClaim:
        claimName: nfs-pvc                  # 对应上面创建 PVC 的名字
kubectl apply -f test.yaml
kubectl get pv,pvc,pods -n mytest
​```
NAME                      CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM            STORAGECLASS   REASON   AGE
persistentvolume/nfs-pv   1Gi        RWX            Retain           Bound    mytest/nfs-pvc   nfs                     16m

NAME                            STATUS   VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   AGE
persistentvolumeclaim/nfs-pvc   Bound    nfs-pv   1Gi        RWX            nfs            16m

NAME        READY   STATUS    RESTARTS   AGE
pod/mypod   1/1     Running   0          16m

​```
# 共享目录中创建 index.html 文件,查看 Pod 中是否存在
kubectl exec -it mypod -n mytest -- more /usr/share/nginx/html/index.html

11.4 NFS 动态方式 PV

当管理员创建的静态PV都不匹配用户的PVC时,集群可能会尝试专门地供给volume给PVC。这种供给基于StorageClass。

参考: https://www.jianshu.com/p/15260a66cd41

# 所有work节点安装 nfs-utils rpcbind
yum install nfs-utils rpcbind -y
systemctl start nfs rpcbind
systemctl enable nfs rpcbind

11.4-1 创建RBAC授权

wget https://raw.githubusercontent.com/kubernetes-incubator/external-storage/master/nfs-client/deploy/rbac.yaml
kubectl apply -f rbac.yaml

11.4-2 创建 Storageclass

# cat class.yaml  ---> kubectl apply -f storageclass-nfs.yaml 

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: managed-nfs-storage
provisioner: fuseim.pri/ifs # or choose another name, must match deployment's env PROVISIONER_NAME'
parameters:
  archiveOnDelete: "false"

11.4-3 创建nfs-client-provisioner自动配置程序,以便自动创建持久卷(PV)

自动创建的 PV 以 {namespace}-${pvcName}-${pvName} 的命名格式创建在 NFS 上 当这个 PV 被回收后会以 archieved-{namespace}-${pvcName}-${pvName} 的命名格式存在 NFS 服务器上

# cat deployment.yaml  ---> kubectl apply -f deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nfs-client-provisioner
  labels:
    app: nfs-client-provisioner
  # replace with namespace where provisioner is deployed
  namespace: default
spec:
  replicas: 1
  strategy:
    type: Recreate
  selector:
    matchLabels:
      app: nfs-client-provisioner
  template:
    metadata:
      labels:
        app: nfs-client-provisioner
    spec:
      serviceAccountName: nfs-client-provisioner
      containers:
        - name: nfs-client-provisioner
          image: quay.io/external_storage/nfs-client-provisioner:latest
          volumeMounts:
            - name: nfs-client-root
              mountPath: /persistentvolumes
          env:
            - name: PROVISIONER_NAME
              value: fuseim.pri/ifs
            - name: NFS_SERVER
              value: 192.168.1.33
            - name: NFS_PATH
              value: /nfs/data
      volumes:
        - name: nfs-client-root
          nfs:
            server: 192.168.1.33
            path: /nfs/data

11.4-4 创建一个有状态应用

# cat statefulset-nfs.yaml    ---> kubectl apply -f statefulset-nfs.yaml

apiVersion: v1
kind: Service
metadata:
  name: nginx
  labels:
    app: nginx
spec:
  ports:
  - port: 80
    name: web
  clusterIP: None
  selector:
    app: nginx
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: nfs-web
spec:
  serviceName: "nginx"
  replicas: 3
  selector:
    matchLabels:
      app: nfs-web # has to match .spec.template.metadata.labels
  template:
    metadata:
      labels:
        app: nfs-web
    spec:
      terminationGracePeriodSeconds: 10
      containers:
      - name: nginx
        image: nginx:1.7.9
        ports:
        - containerPort: 80
          name: web
        volumeMounts:
        - name: www
          mountPath: /usr/share/nginx/html
  volumeClaimTemplates:
  - metadata:
      name: www
      annotations:
        volume.beta.kubernetes.io/storage-class: managed-nfs-storage
    spec:
      accessModes: [ "ReadWriteOnce" ]
      resources:
        requests:
          storage: 1Gi
  • 查看 Pod/PV/PVC

    kubectl get pods
    kubectl get pvc,pv
    # 查看 nfs server 目录中信息,同时各子目录中内容为空
    ls -l /data/nfs/

11.4-5 破坏性测试

# 在每个 pod 中写入内容
for i in 0 1 2; do kubectl exec nfs-web-$i -- sh -c 'echo $(hostname) > /usr/share/nginx/html/index.html'; done

# 远程nfs各子目录中不再为空,出现了内容
ls /data/nfs/default-www-nfs-web-0-pvc-62f4868f-c6f7-459e-a280-26010c3a5849/

# 查看每个容器中内容,均为各自主机名
for i in 0 1 2; do kubectl exec -it nfs-web-$i -- cat /usr/share/nginx/html/index.html; done
nfs-web-0
nfs-web-1
nfs-web-2

# 删除对应 pod
kubectl get pod -l app=nfs-web
kubectl delete pod -l app=nfs-web

# 再次查看,会发现会自动创建
kubectl get pod -l app=nfs-web   

# 再次查看每个pod中内容,可以看到文件内容没有变化
for i in 0 1 2; do kubectl exec -it nfs-web-$i -- cat /usr/share/nginx/html/index.html; done
nfs-web-0
nfs-web-1
nfs-web-2

11.4-6 结束语

可以看到, statefulset 控制器通过固定的 pod 创建顺序可以确保 pod 之间的拓扑关系一直处于稳定不变的状态,通过 nfs-client-provisioner 自动创建和每个 pod 有固定对应关系的远程存储卷,确保 pod 重建后数据不会丢失。

第四部分 部署统一日志管理

第五部分 部署性能监控平台

第六部分 搭建高可用的K8S集群

第七部分 K8S集群部署项目

第八部分 Ceph 集群

IP
主机名

192.168.110.59

cephnode01

192.168.110.62

cephnode02

192.168.110.64

cephnode03

1、Cepy-deploy 部署

1、初始化(所有主机)

sed -i 's/SELINUX=enforcing/SELINUX=disabled/g' /etc/selinux/config
setenforce 0
systemctl disable firewalld
systemctl stop firewalld
yum -y install ntp
systemctl enable ntpd
systemctl start ntpd
systemctl disable chronyd
ntpq -p


yum install wget -y
mkdir /tmp/repo.bak && mv /etc/yum.repos.d/*.repo /tmp/repo.bak
wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo
wget -P /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo

cat > /etc/yum.repos.d/ceph.repo << EOF
[ceph]
name=ceph
baseurl=http://mirrors.aliyun.com/ceph/rpm-luminous/el7/x86_64/
gpgcheck=0

[ceph-noarch]
name=cephnoarch
baseurl=http://mirrors.aliyun.com/ceph/rpm-luminous/el7/noarch/
gpgcheck=0

[ceph-source]
name=ceph-source
baseurl=http://mirrors.aliyun.com/ceph/rpm-luminous/el7/SRPMS/
gpgcheck=0
EOF

yum clean all
yum makecache
yum -y install python-setuptools

2、主机免密

# cephnode01 执行,作为管理控制节点
ssh-keygen -t rsa -P ""
ssh-copy-id 192.168.110.59
ssh-copy-id 192.168.110.62
ssh-copy-id 192.168.110.64
# 设置 hostname
hostnamectl set-hostname <hostname>
# 拷贝 hosts 到远程
echo "192.168.110.59 cephnode01" >> /etc/hosts
echo "192.168.110.62 cephnode02" >> /etc/hosts
echo "192.168.110.64 cephnode03" >> /etc/hosts

yum -y install ceph-deploy
ceph-deploy --version (必须是 2.0.1 + )

3、创建一个my-cluster目录,所有命令在此目录下进行(文件位置和名字可以随意)

mkdir /my-cluster
cd /my-cluster

4、创建一个Ceph集群,(hosts里的解析名和主机名一定要想相同,否则报错)

ceph-deploy new cephnode01 cephnode02 cephnode03 

5、安装Ceph软件(每个节点执行)

yum -y install epel-release
yum install -y ceph
# 或者管理节点执行: ceph-deploy install cephnode01 cephnode02 cephnode03 

6、初始化,并生成monitor检测集群所使用的的秘钥

ceph-deploy mon create-initial

7、安装Ceph CLI,方便执行一些管理命令

ceph-deploy admin cephnode01 cephnode02 cephnode03

8、配置mgr,用于管理集群

ceph-deploy mgr create cephnode01 cephnode02 cephnode03

9、部署rgw

yum install -y ceph-radosgw
ceph-deploy rgw create cephnode01

10、部署MDS(CephFS)

ceph-deploy mds create cephnode01 cephnode02 cephnode03 

11、添加osd

ceph-deploy osd create --data /dev/sdb node1
ceph-deploy osd create --data /dev/sdb node2
ceph-deploy osd create --data /dev/sdb node3
# 注意 如果要在LVM卷上创建OSD,则参数 --data 必须是volume_group/lv_name,而不是卷的块设备的路径。

12、检查集群健康(node1)

[root@localhost my-cluster]# ceph health
HEALTH_OK

[root@localhost my-cluster]# ceph -s
  cluster:
    id:     0e3f5736-d67b-47af-bac7-7146f7c7a8b5
    health: HEALTH_OK
 
  services:
    mon: 3 daemons, quorum cephnode03,cephnode02,cephnode01
    mgr: cephnode01(active), standbys: cephnode02, cephnode03
    osd: 3 osds: 3 up, 3 in
    rgw: 1 daemon active
 
  data:
    pools:   4 pools, 32 pgs
    objects: 219 objects, 1.09KiB
    usage:   3.00GiB used, 27.0GiB / 30.0GiB avail
    pgs:     32 active+clean
 

2、ceph.conf

1、该配置文件采用init文件语法,#和;为注释,ceph集群在启动的时候会按照顺序加载所有的conf配置文件。 配置文件分为以下几大块配置。

global:全局配置。
osd:osd专用配置,可以使用osd.N,来表示某一个OSD专用配置,N为osd的编号,如0、2、1等。
mon:mon专用配置,也可以使用mon.A来为某一个monitor节点做专用配置,其中A为该节点的名称,ceph-monitor-2、ceph-monitor-1等。使用命令 ceph mon dump可以获取节点的名称。
client:客户端专用配置。

2、配置文件可以从多个地方进行顺序加载,如果冲突将使用最新加载的配置,其加载顺序为。

$CEPH_CONF环境变量
-c 指定的位置
/etc/ceph/ceph.conf
~/.ceph/ceph.conf
./ceph.conf

3、配置文件还可以使用一些元变量应用到配置文件,如。

$cluster:当前集群名。
$type:当前服务类型。
$id:进程的标识符。
$host:守护进程所在的主机名。
$name:值为$type.$id。

4、ceph.conf详细参数

[global]#全局设置
fsid = xxxxxxxxxxxxxxx                           #集群标识ID 
mon host = 10.0.1.1,10.0.1.2,10.0.1.3            #monitor IP 地址
auth cluster required = cephx                    #集群认证
auth service required = cephx                           #服务认证
auth client required = cephx                            #客户端认证
osd pool default size = 3                             #最小副本数 默认是3
osd pool default min size = 1                           #PG 处于 degraded 状态不影响其 IO 能力,min_size是一个PG能接受IO的最小副本数
public network = 10.0.1.0/24                            #公共网络(monitorIP段) 
cluster network = 10.0.2.0/24                           #集群网络
max open files = 131072                                 #默认0#如果设置了该选项,Ceph会设置系统的max open fds
mon initial members = node1, node2, node3               #初始monitor (由创建monitor命令而定)
##############################################################
[mon]
mon data = /var/lib/ceph/mon/ceph-$id
mon clock drift allowed = 1                             #默认值0.05#monitor间的clock drift
mon osd min down reporters = 13                         #默认值1#向monitor报告down的最小OSD数
mon osd down out interval = 600      #默认值300      #标记一个OSD状态为down和out之前ceph等待的秒数
##############################################################
[osd]
osd data = /var/lib/ceph/osd/ceph-$id
osd mkfs type = xfs                                     #格式化系统类型
osd max write size = 512 #默认值90                   #OSD一次可写入的最大值(MB)
osd client message size cap = 2147483648 #默认值100    #客户端允许在内存中的最大数据(bytes)
osd deep scrub stride = 131072 #默认值524288         #在Deep Scrub时候允许读取的字节数(bytes)
osd op threads = 16 #默认值2                         #并发文件系统操作数
osd disk threads = 4 #默认值1                        #OSD密集型操作例如恢复和Scrubbing时的线程
osd map cache size = 1024 #默认值500                 #保留OSD Map的缓存(MB)
osd map cache bl size = 128 #默认值50                #OSD进程在内存中的OSD Map缓存(MB)
osd mount options xfs = "rw,noexec,nodev,noatime,nodiratime,nobarrier" #默认值rw,noatime,inode64  #Ceph OSD xfs Mount选项
osd recovery op priority = 2 #默认值10              #恢复操作优先级,取值1-63,值越高占用资源越高
osd recovery max active = 10 #默认值15              #同一时间内活跃的恢复请求数 
osd max backfills = 4  #默认值10                  #一个OSD允许的最大backfills数
osd min pg log entries = 30000 #默认值3000           #修建PGLog是保留的最大PGLog数
osd max pg log entries = 100000 #默认值10000         #修建PGLog是保留的最大PGLog数
osd mon heartbeat interval = 40 #默认值30            #OSD ping一个monitor的时间间隔(默认30s)
ms dispatch throttle bytes = 1048576000 #默认值 104857600 #等待派遣的最大消息数
objecter inflight ops = 819200 #默认值1024           #客户端流控,允许的最大未发送io请求数,超过阀值会堵塞应用io,为0表示不受限
osd op log threshold = 50 #默认值5                  #一次显示多少操作的log
osd crush chooseleaf type = 0 #默认值为1              #CRUSH规则用到chooseleaf时的bucket的类型
##############################################################
[client]
rbd cache = true #默认值 true      #RBD缓存
rbd cache size = 335544320 #默认值33554432           #RBD缓存大小(bytes)
rbd cache max dirty = 134217728 #默认值25165824      #缓存为write-back时允许的最大dirty字节数(bytes),如果为0,使用write-through
rbd cache max dirty age = 30 #默认值1                #在被刷新到存储盘前dirty数据存在缓存的时间(seconds)
rbd cache writethrough until flush = false #默认值true  #该选项是为了兼容linux-2.6.32之前的virtio驱动,避免因为不发送flush请求,数据不回写
              #设置该参数后,librbd会以writethrough的方式执行io,直到收到第一个flush请求,才切换为writeback方式。
rbd cache max dirty object = 2 #默认值0              #最大的Object对象数,默认为0,表示通过rbd cache size计算得到,librbd默认以4MB为单位对磁盘Image进行逻辑切分
      #每个chunk对象抽象为一个Object;librbd中以Object为单位来管理缓存,增大该值可以提升性能
rbd cache target dirty = 235544320 #默认值16777216    #开始执行回写过程的脏数据大小,不能超过 rbd_cache_max_dirty

扩展群集

启动并运行基本群集后,下一步是展开群集。添加Ceph元数据服务器node1。然后添加Ceph Monitor和Ceph Manager node2,node3以提高可靠性和可用性。添加元数据服务器:配置MDS服务(NODE1)要使用CephFS,您至少需要一个元数据服务器。执行以下操作以创建元数据服务器:

ceph-deploy mds create node1

添加监视器

Ceph存储集群需要至少运行一个Ceph Monitor和Ceph Manager。为了实现高可用性,Ceph存储集群通常运行多个Ceph监视器,因此单个Ceph监视器的故障不会导致Ceph存储集群崩溃。Ceph使用Paxos算法,该算法需要大多数监视器(即,大于N / 2,其中N是监视器的数量)才能形成法定人数。虽然这不是必需的,但监视器的数量往往更好。

# 将两个Ceph监视器添加到您的群集:
ceph-deploy mon add node2 node3

# 一旦你添加了新的Ceph监视器,Ceph将开始同步监视器并形成一个法定人数。您可以通过执行以下操作来检查仲裁状态:
ceph quorum_status --format json-pretty

# 注意: 当您使用多个监视器运行Ceph时,您应该在每个监视器主机上安装和配置NTP, 确保监视器是NTP对等方。

添加管理员

Ceph Manager守护进程以活动/备用模式运行。部署其他管理器守护程序可确保在一个守护程序或主机发生故障时,另一个守护程序或主机可以在不中断服务的情况下接管。

# 要部署其他管理器守护程序:
ceph-deploy mgr create node2 node3

# 删除OSD(node1)
ceph auth del osd.0
ceph osd rm 0

配置DashBoard

# 创建域管理秘钥(node1)
ceph auth get-or-create mgr.node1 mon 'allow profile mgr' osd 'allow *' mds 'allow *'

# 开启ceph-mgr管理域(node1)
ceph-mgr -i node1

# 打开dashboard模块(node1)
ceph mgr module enable dashboard

# 绑定开启dashboard模块的ceph-mgr节点的ip地址(node1主机)
ceph config-key set mgr/dashboard/node1/server_addr 192.168.110.59

# 访问Dashboard (任意主机)
http://192.168.110.59:7000

常用命令整理

创建 Pool 池

# 注意:创建了池后,无法减少PG的数量,只能增加
[root@localhost ~]# ceph osd pool create testPool 16 16
pool 'testPool' created

为 池 启用ceph应用,并指定池类型

# <rbd(块) |cephfs(文件) |object(对象)>
[root@localhost ~]# ceph osd pool application enable testPool rbd
enabled application 'testPool' on pool 'testPool'

查看所有池, 或者命令: rados lspools

[root@localhost ~]# ceph osd pool ls                                           
.rgw.root
default.rgw.control
default.rgw.meta
default.rgw.log
pool01
testPool

查看所有池的详细信息

[root@localhost ~]# ceph osd pool ls detail
pool 1 '.rgw.root' replicated size 3 min_size 2 crush_rule 0 object_hash rjenkins pg_num 8 pgp_num 8 last_change 3 flags hashpspool stripe_width 0 application rgw
pool 2 'default.rgw.control' replicated size 3 min_size 2 crush_rule 0 object_hash rjenkins pg_num 8 pgp_num 8 last_change 17 flags hashpspool stripe_width 0 application rgw
pool 3 'default.rgw.meta' replicated size 3 min_size 2 crush_rule 0 object_hash rjenkins pg_num 8 pgp_num 8 last_change 19 flags hashpspool stripe_width 0 application rgw
pool 4 'default.rgw.log' replicated size 3 min_size 2 crush_rule 0 object_hash rjenkins pg_num 8 pgp_num 8 last_change 21 flags hashpspool stripe_width 0 application rgw
pool 9 'pool01' replicated size 3 min_size 2 crush_rule 0 object_hash rjenkins pg_num 16 pgp_num 16 last_change 57 flags hashpspool stripe_width 0 application pool01
        removed_snaps [1~3]
pool 11 'testPool' replicated size 3 min_size 2 crush_rule 0 object_hash rjenkins pg_num 16 pgp_num 16 last_change 68 flags hashpspool stripe_width 0 application rbd

修改池名字

[root@localhost ~]# ceph osd pool rename testPool testPool1
pool 'testPool' renamed to 'testPool1'

设置 池 配额,限制对象数量

[root@localhost ~]# ceph osd pool set-quota testPool max_objects 1024
set-quota max_objects = 1024 for pool testPool

设置 池 配额,限制容量数量

[root@localhost ~]# ceph osd pool set-quota testPool max_bytes 1024
set-quota max_bytes = 1024 for pool testPool

取消配额,max_objects 一样

[root@localhost ~]# ceph osd pool set-quota testPool max_bytes 0              
set-quota max_bytes = 0 for pool testPool

查看池 状态,

[root@localhost ~]# ceph osd pool stats                                       
pool .rgw.root id 1
  nothing is going on
  
查看某个池: ceph osd pool stats testPool

创建一个块设备

[root@localhost ~]# rbd create --size 1024 block -p testPool 

查看池中,有哪些块设备

[root@localhost ~]# rbd ls -p testPool                                         
block

查看块设备详细信息

[root@localhost ~]# rbd info block -p testPool                                 
rbd image 'block':
        size 2GiB in 512 objects
        order 22 (4MiB objects)
        block_name_prefix: rbd_data.122616b8b4567
        format: 2
        features: layering, exclusive-lock, object-map, fast-diff, deep-flatten
        flags: 
        create_timestamp: Sat Apr 17 22:08:50 2021

查看池使用情况

[root@localhost ~]# ceph df                                                   
GLOBAL:
    SIZE        AVAIL       RAW USED     %RAW USED 
    30.0GiB     27.0GiB      3.01GiB         10.03 
POOLS:
    NAME                    ID     USED        %USED     MAX AVAIL     OBJECTS 
    .rgw.root               1      1.09KiB         0       8.49GiB           4 
    default.rgw.control     2           0B         0       8.49GiB           8 
    default.rgw.meta        3           0B         0       8.49GiB           0 
    default.rgw.log         4           0B         0       8.49GiB         207 
    pool01                  9         232B         0       8.49GiB           6 
    testPool                10        134B         0       8.49GiB           5 

查看集群空间使用情况

[root@localhost ~]# ceph osd df 
ID CLASS WEIGHT  REWEIGHT SIZE    USE     DATA    OMAP META AVAIL   %USE  VAR  PGS 
 0   ssd 0.00980  1.00000 10.0GiB 1.00GiB 2.48MiB   0B 1GiB 8.99GiB 10.03 1.00  64 
 1   ssd 0.00980  1.00000 10.0GiB 1.00GiB 2.48MiB   0B 1GiB 8.99GiB 10.03 1.00  64 
 2   ssd 0.00980  1.00000 10.0GiB 1.00GiB 2.48MiB   0B 1GiB 8.99GiB 10.03 1.00  64 
                    TOTAL 30.0GiB 3.01GiB 7.45MiB   0B 3GiB 27.0GiB 10.03          
MIN/MAX VAR: 1.00/1.00  STDDEV: 0

### 查看池属性

[root@localhost ~]# ceph osd pool get testPool all                           
size: 3
min_size: 2
crash_replay_interval: 0
pg_num: 16
pgp_num: 16
crush_rule: replicated_rule
hashpspool: true
nodelete: false
nopgchange: false
nosizechange: false
write_fadvise_dontneed: false
noscrub: false
nodeep-scrub: false
use_gmt_hitset: 1
auid: 0
fast_read: 0

对接 k8s 集群:Rbd 持久化存储 <已验证>

准备工作: 创建pod时,kubelet需要使用rbd命令去检测和挂载pv对应的ceph image,所以要在所有的worker节点安装ceph客户端ceph-common。 将ceph的ceph.client.admin.keyring和ceph.conf文件拷贝到master的/etc/ceph目录下

yum -y install ceph-common

1、Ceph集群中,创建一个 pool 池,为后面k8s接入使用

ceph osd pool create kube 128 128 
ceph osd pool ls

2、首先得在kubernetes集群中安装 rbd-provisioner,github仓库链接https://github.com/kubernetes-incubator/external-storage

# 根据自己需要,修改rbd-provisioner的namespace;
yum install git -y
git clone https://github.com/kubernetes-retired/external-storage.git
cd external-storage/ceph/rbd/deploy
export NAMESPACE=kube-system
sed -r -i "s/namespace: [^ ]+/namespace: $NAMESPACE/g" ./rbac/clusterrolebinding.yaml ./rbac/rolebinding.yaml
kubectl -n $NAMESPACE apply -f ./rbac

# 部署完成后检查rbd-provisioner deployment,确保已经正常部署;
kubectl get deploy -n kube-system
kubectl describe deployments.apps -n kube-system rbd-provisioner

3、创建storageclass

创建secret保存client.admin和client.kube用户的key,client.admin和client.kube用户的secret可以放在kube-system namespace,但如果其他namespace需要使用ceph rbd的dynamic provisioning功能的话,要在相应的namespace创建secret来保存client.kube用户key信息

# 部署完rbd-provisioner,还需要创建StorageClass。创建SC前,我们还需要创建相关用户的secret;
[root@k8s01 ~]# vi secrets.yaml
apiVersion: v1
kind: Secret
metadata:
 name: ceph-admin-secret
 namespace: kube-system
type: "kubernetes.io/rbd"
data:
 # ceph auth get-key client.admin | base64
 key: QVFCdng4QmJKQkFsSFJBQWl1c1o0TGdOV250NlpKQ1BSMHFCa1E9PQ==
---
apiVersion: v1
kind: Secret
metadata:
 name: ceph-secret
 namespace: kube-system
type: "kubernetes.io/rbd"
data:
 # ceph auth add client.kube mon 'allow r' osd 'allow rwx pool=kube'
 # ceph auth get-key client.kube | base64
 key: QVFCTHdNRmJueFZ4TUJBQTZjd1MybEJ2Q0JUcmZhRk4yL2tJQVE9PQ==

[root@k8s01 ~]#  kubectl create -f secrets.yaml

[root@k8s01 ~]# vi secrets-default.yaml
apiVersion: v1
kind: Secret
metadata:
  name: ceph-secret
type: "kubernetes.io/rbd"
data:
  # ceph auth add client.kube mon 'allow r' osd 'allow rwx pool=kube'
  # ceph auth get-key client.kube | base64
  key: QVFCTHdNRmJueFZ4TUJBQTZjd1MybEJ2Q0JUcmZhRk4yL2tJQVE9PQ==
  • 其他设置和普通的ceph rbd StorageClass一致,但provisioner需要设置为**ceph.com/rbd**,不是默认的kubernetes.io/rbd,这样rbd的请求将由rbd-provisioner来处理;

  • 考虑到兼容性,建议尽量关闭rbd image feature,并且kubelet节点的ceph-common版本尽量和ceph服务器端保持一致;

[root@k8s01 ~]# vi ceph-rbd-sc.yaml
apiVersion: storage.k8s.io/v1beta1
kind: StorageClass
metadata:
  name: ceph-rbd
  annotations:
     storageclass.beta.kubernetes.io/is-default-class: "true"
provisioner: ceph.com/rbd
parameters:
  monitors: 10.10.181.249:6789,10.10.181.248:6789,10.10.181.247:6789
  adminId: admin
  adminSecretName: ceph-admin-secret
  adminSecretNamespace: kube-system
  pool: kube
  userId: kube
  userSecretName: ceph-secret
  fsType: ext4
  imageFormat: "2"
  imageFeatures: "layering"

[root@k8s01 ~]#  kubectl create -f  ceph-rbd-sc.yaml

4、测试ceph rbd自动分配

在kube-system和default namespace分别创建pod,通过启动一个busybox实例,将ceph rbd镜像挂载到/usr/share/busybox;

[root@k8s01 ~]# vi test-pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: ceph-pod1
spec:
  containers:
  - name: ceph-busybox
    image: busybox
    command: ["sleep", "60000"]
    volumeMounts:
      - name: ceph-vol1
        mountPath: /usr/share/busybox
        readOnly: false
  volumes:
  - name: ceph-vol1
    persistentVolumeClaim:
      claimName: ceph-claim
---
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: ceph-claim
spec:
  accessModes:  
    - ReadWriteOnce
  resources:
    requests:
      storage: 2Gi

[root@k8s01 ~]# kubectl create -f test-pod.yaml -n kube-system
pod/ceph-pod1 created
persistentvolumeclaim/ceph-claim created

# < 使用默认空间,会使用刚才创建的 secrets-default.yaml,惹其他空间,则创建其他空间秘钥 >
[root@k8s01 ~]# kubectl create -f test-pod.yaml -n default 
pod/ceph-pod1 created
persistentvolumeclaim/ceph-claim created

检查pv和pvc的创建状态,是否都已经创建;

[root@k8s01 ~]# kubectl get pvc,pv -n kube-system
NAME         STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
ceph-claim   Bound    pvc-ee0f1c35-cef7-11e8-8484-005056a33f16   2Gi        RWO            ceph-rbd       25s

NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM                    STORAGECLASS   REASON   AGE
pvc-ea377cad-cef7-11e8-8484-005056a33f16   2Gi        RWO            Delete           Bound    kube-system/ceph-claim   ceph-rbd                40s

在ceph服务器上,检查rbd镜像创建情况和镜像的信息;

[root@k8s01 ~]# rbd ls --pool kube
kubernetes-dynamic-pvc-ea390cbf-cef7-11e8-aa22-0a580af40202

[root@k8s01 ~]# rbd info kube/kubernetes-dynamic-pvc-ea390cbf-cef7-11e8-aa22-0a580af40202
rbd image 'kubernetes-dynamic-pvc-ea390cbf-cef7-11e8-aa22-0a580af40202':
    size 2048 MB in 512 objects
    order 22 (4096 kB objects)
    block_name_prefix: rbd_data.456876b8b4567
    format: 2
    features: layering
    flags:
    create_timestamp: Sat Oct 13 22:54:41 2018

检查busybox内的文件系统挂载和使用情况,确认能正常工作;

[root@k8s01 ~]# kubectl exec eph-pod1 -- mount |grep rbd
/dev/rbd0 on /usr/share/busybox type ext4 (rw,seclabel,relatime,stripe=1024,data=ordered)

[root@k8s01 ~]# kubectl exec -it ceph-pod1 df |grep rbd
/dev/rbd0              1998672      6144   1976144   0% /usr/share/busybox

测试删除pod能否自动删除pv和pvc,生产环境中谨慎,设置好回收策略;

[root@k8s01 ~]# kubectl delete -f test-pod.yaml
pod "ceph-pod1" deleted
persistentvolumeclaim "ceph-claim" deleted
[root@k8s01 ~]# kubectl get pv
No resources found.
[root@k8s01 ~]# kubectl get pvc
No resources found.

ceph服务器上的rbd image也已清除,自动回收成功;

rbd ls -p kube

总结

大部分情况下,我们无需使用rbd provisioner来提供ceph rbd的dynamic provisioning能力。经测试,在OpenShift、Rancher、SUSE CaaS以及本Handbook的二进制文件方式部署,在安装好ceph-common软件包的情况下,定义StorageClass时使用kubernetes.io/rbd即可正常使用ceph rbd provisioning功能。

参考: https://jimmysong.io/kubernetes-handbook/practice/rbd-provisioner.html

对接k8s集群: Cephfs 持久化存储 <已验证>

准备工作所以work节点:

yum -y install epel-release
yum -y install ceph-common ceph-fuse

# 官方没有cephfs动态卷支持, 使用社区提供的cephfs-provisioner

kubectl create ns cephfs
git clone https://github.com/kubernetes-retired/external-storage.git
cd external-storage/ceph/cephfs/deploy
NAMESPACE=cephfs
sed -r -i "s/namespace: [^ ]+/namespace: $NAMESPACE/g" ./rbac/*.yaml
sed -r -i "N;s/(name: PROVISIONER_SECRET_NAMESPACE.*\n[[:space:]]*)value:.*/\1value: $NAMESPACE/" ./rbac/deployment.yaml
kubectl -n $NAMESPACE apply -f ./rbac

#检查pod 的状态是否正常
kubectl get pods -n cephfs
     NAME                                  READY   STATUS    RESTARTS   AGE
     cephfs-provisioner-7bf7d44886-wvjz8   1/1     Running   0          4h13m

配置 storageclass 及 Pod 测试

[root@k8s-master3 deploy]# cat storageclass-cephfs.yaml 
apiVersion: v1
kind: Secret
metadata:
  name: ceph-secret-fs
  namespace: cephfs
type: kubernetes.io/rbd
data:
  # ceph auth get-key client.admin | base64 || sed -n  '/key/p' ceph.client.admin.keyring |awk '{print $3}' |base64
  key: QVFEenkzbGcyYlhrTHhBQVgvUlNPOEJXUldxQisxT1Q1MlIra2c9PQo=
---
kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
  name: dynamic-cephfs
  namespace: cephfs
provisioner: ceph.com/cephfs
parameters:
    monitors: 10.10.181.249:6789,10.10.181.248:6789,10.10.181.247:6789
    adminId: admin
    adminSecretName: ceph-secret-fs
    adminSecretNamespace: cephfs
#    claimRoot: /volumes/kubernetes
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: cephfs-claim
  namespace: cephfs
spec:
  accessModes:
    - ReadWriteMany
  storageClassName: dynamic-cephfs
  resources:
    requests:
      storage: 1Gi
---
kind: Pod
apiVersion: v1
metadata:
  name: test-pod
  namespace: cephfs
spec:
  containers:
  - name: test-pod
    image: ikubernetes/myapp:v4
    volumeMounts:
      - name: pvc
        mountPath: "/data/cephfs"
  volumes:
    - name: pvc
      persistentVolumeClaim:
        claimName: cephfs-claim

查看是否挂载:

[root@k8s-master3 deploy]# kubectl exec -it test-pod -n cephfs -- /bin/sh -c 'df -h |grep ceph-fuse'
ceph-fuse                 3.6G         0      3.6G   0% /data/cephfs

验证:

[root@k8s-master3 deploy]# kubectl exec -it test-pod -n cephfs -- /bin/sh -c 'echo cephfs-test > /data/cephfs/test.txt && more /data/cephfs/test.txt'
cephfs-test

​ - provisioner 该字段指定使用存储卷类型为 kubernetes.io/rbd,注意 kubernetes.io/ 开头为 k8s 内部支持的存储提供者,不同的存储卷提供者类型这里要修改成对应的值。 ​ - adminId | userId 这里需要指定两种 Ceph 角色 admin 和其他 user,admin 角色默认已经有了,其他 user 可以去 Ceph 集群创建一个并赋对应权限值,如果不创建,也可以都指定为 admin。 ​ - adminSecretName 为上边创建的 Ceph 管理员 admin 使用的 ceph-secret-admin。 ​ - adminSecretNamespace 管理员 secret 使用的命名空间,默认 default,如果修改为其他的话,需要修改 ceph-secret- admin.yaml 增加 namespace: other-namespace。

第九部分 常见问题

技巧:无法删除 PV,PVC ?

# 系统内有一个已经不再使用的 PV ,已经删除了与其关联的 Pod 及 PVC ,并对其执行了删除命令,但是无法正常删除,一直出于如下状态:
kubectl get pv
NAME          CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS        CLAIM                                    STORAGECLASS          REASON   AGE
pv-nfs-gysl   1Gi        RWO            Recycle          Terminating   default/www-vct-statefulset-pvc-gysl-0   managed-nfs-storage            22h


###  解决方法: 更新一个资源的 field(s)
kubectl patch pv pv-nfs-gysl -p '{"metadata":{"finalizers":null}}'
persistentvolume/pv-nfs-gysl patched
kubectl get pv

技巧: 无法删除 Pod ?

kubectl delete pod <Podname> -n <namespace> --force --grace-period=0

# 暴力删除
  # 删除default namespace下的pod名为pod-to-be-deleted-0
    ETCDCTL_API=3 etcdctl del /registry/pods/default/pod-to-be-deleted-0
    # 删除需要删除的NAMESPACE
    etcdctl del /registry/namespaces/NAMESPACENAME</pre>

技巧: kubeadm 如何删除节点?

# 1)假设我们需要删除 k8s-node1 这个节点,首先在 master 节点上依次执行以下两个命令:
kubectl drain k8s-node1 --delete-local-data --force --ignore-daemonsets
kubectl delete node  k8s-node1
# 执行后通过 kubectl get node 命令可以看到 k8s-node1 已被成功删除:
# 2)接着在 k8s-node1 这个 Node 节点上执行如下命令,这样该节点即完全从 Cluster 中脱离开来:
kubeadm reset

技巧:如何重启Pod?

Deployment 方式下重启 Pod

kubectl delete pod {podname} -n {namespace}        # 直接删除pod,让k8s去完成 pod 重建
# 但是如果ReplicaSet 管理的 Pod 对象很多的话,那么要一个个手动删除,会很麻烦,所以可以使用命令来删除 ReplicaSet,
kubectl delete replicaset {rs_name} -n {namespace}

# 也可以通过调整 ReplicaSet 的数量来实现重启,比如先 scale 到 0,然后再 scale 到 1,那么 Pod 也不得不重启,
kubectl scale deployment {deployment} --replicas=0 -n {namespace}
kubectl scale deployment {deployment} --replicas=1 -n {namespace}

使用 YAML 文件重启Pod

# 当我们有 Pod 的 yaml 文件是,可以直接使用 replace 命令,来强制替换 Pod 的API对象,从而实现重启的效果:
kubectl replace --force -f youpod.yaml

# 如果你手头没有 yaml 文件,直接使用的 Pod 对象,我们可以稍微调整一下上面的命令,如下:
kubectl get pod {podname} -n {namespace} -o yaml | kubectl replace --force -f -

莫名被打上污点?

此外,kubernetes 1.6引入了对节点问题的展示.也就是说当满足了特定条件,节点控制器会自动为符合条件的节点添加taint,以下是一些内置的taint

  • node.kubernetes.io/not-ready,节点还没有准备好,对应节点状态Ready值为false

  • node.kubernetes.io/unreachable,节点控制器无法触及节点,对应节点状态ready值为Unknown

  • node.kubernetes.io/out-of-disk,磁盘空间不足

  • node.kubernetes.io/memory-pressure,节点存在内存压力

  • node.kubernetes.io/disk-pressure,节点磁盘存在压力

  • node.kubernetes.io/network-unavailable,节点网络不可用

  • node.kubernetes.io/unschedulable,节点不可被调度

  • node.cloudprovider.kubernetes.io/uninitialized

kubeadm安装的K8s忘记了token或者token过期了怎么办?

例如: 主机名:k8s-master IP地址: 192.168.1.136 端口号: 6443

k8s忘记token?

# 列出token ---> 获取CA公钥的哈希值 ---> 加入集群
TOKEN=$(kubeadm token list | awk -F" " '{print $1}' |tail -n 1)
HASH=$(openssl x509 -pubkey -in /etc/kubernetes/pki/ca.crt | openssl rsa -pubin -outform der 2>/dev/null | openssl dgst -sha256 -hex | sed 's/^.* //')
kubeadm join 192.168.1.136:6443 --token ${TOKEN} --discovery-token-ca-cert-hash sha256:${HASH}

token过期怎么加入k8s集群?

# 重新生成
kubeadm token create --print-join-command
kubeadm token list

k8s.v1.20 NFS 无法动态创建pvc,Pending状态

Using Kubernetes v1.20.0, getting "unexpected error getting claim reference: selfLink was empty, can't make reference" #25

首先nfs正常状态下,并且可以挂载

# 测试创建pvc
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: test-pvc
spec:
  storageClassName: nfs-provisioner
  accessModes:
  - ReadWriteMany
  resources:
    requests:
      storage: 20Gi

必须添加 --feature-gates=RemoveSelfLink=false 在 /etc/kubernetes/manifests/kube-apiserver.yaml 文件内

spec:
  containers:
  - command:
    - kube-apiserver
    - --feature-gates=RemoveSelfLink=false
Previousk3s执行helm命令报错Error Kubernetes cluster unreachable Get “httplocalhost8080versiontimeout=32s“Nextkubernetes学习随笔

Last updated 2 years ago

😘