入门篇
架构与组件
管理节点 master
API server
集群的统一入口,各个组件的协调者,Restful的形式提供接口服务。所有对象的增删改查和监听操作都交给Api Server处理后,存储在Etcd中
Controller-manager
处理常规后台任务:容器的部署、扩容副本、服务升级等,一个资源对应一个congtroller。比如一个Pod有3个副本,一个挂掉了,就会再创建一个), ControllerManager就是管理这些controller。
Scheduler
根据调度算法将创建的Pod调度到适合的机器节点上,比如按照容器数量调度等等
Etcd
分布式存储组件,集群状态数据持久化,只有API Server可以用。比如Pod,serverie等的信息
工作节点 worker
Kube-let
与master节点交互,管理当前工作节点上运行的Pod的生命周期,比如创建,挂载数据卷,下载secret,获取Pod和节点状态。接收API Server的请求,在本地调用docker的Api,执行具体的命令
Kube-proxy
负责各个Pod的网络通信,接收浏览器发出请求,负载到具体的Pod的
回顾
安装
二进制安装
优缺点:手动部署每个组件,手动编写每个组件的配置文件,前期部署难度大,后期维护轻松
Rancher安装
https://blog.csdn.net/cdy2143/article/details/109534036
Kube-admin安装
优缺点:用于快速部署k8s集群的工具,简化部署集群,后期维护比较难
准备
- 3台机器:1主2从
- 禁止swap分区:当物理内存不足,使用磁盘作为交换数据
安装
# 关闭防火墙
systemctl stop firewalld 临时
systemctl disable firewalld 永久
# 关闭安全模块selinux
setenforce 0 临时
https://jingyan.baidu.com/article/7e4409537177d32fc0e2efe9.html 永久
getenforce 查看
# 禁止swap分区
swapoff -a 临时
https://blog.csdn.net/yefun/article/details/102772368 永久
free -m 查看状态
# 添加ipv4流量同步iptables,k8s使用iptables网络
cat >> /etc/sysctl.d/k8s.conf << EOF
net.bridge.bridge-nf-call-ip6tables=1
net.bridge.bridge-nf-call-iptables=1
EOF
sysctl -p /etc/sysctl.d/k8s.conf 生效
拓展:sysctl: cannot stat /proc/sys/net/bridge/bridge-nf-call-ip6tables: 没有那个文件或目录报错
解决:modprobe br_netfilter
参考:https://www.cnblogs.com/EasonJim/p/9626986.html重启生效
# 时间同步 yum install ntpdate -y
ntpdate time.windows.com
# 安装docker
https://www.jianshu.com/p/c6c56194252e
# 安装k8s
# 添加阿里云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
# 安装工具kubeadm、kubelet、kubectl
yum install -y kubelet-1.19.0 kubeadm-1.19.0 kubectl-1.19.0
systemctl enable kubelet 开机启动
# 以上为通用设置 先设置通用部分作为虚拟机模板,只改需要的部分
# 设置主机名
hostnamectl set-hostname k8swork02 名
# 添加hosts
cat >> /etc/hosts << EOF
192.168.207.129 k8smaster
192.168.207.134 k8swork01
192.168.207.135 k8swork02
EOF
# 安装k8smaster
kubeadm init \
--apiserver-advertise-address=192.168.31.61 \ 集群入口地址
--image-repository registry.aliyuncs.com/google_containers \ 设置阿云镜像
--kubernetes-version v1.19.0 \ 设置版本,要与上面一致
--service-cidr=10.96.0.0/12 \ service网络地址
--pod-network-cidr=10.244.0.0/16 \ pod网络地址
--ignore-preflight-errors=all
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
# 加入工作节点,master节点创建后会返回
kubeadm join 192.168.207.129:6443 --token gedbw8.8y6gnfwdl78ec69l \
--discovery-token-ca-cert-hash sha256:0083a787f58a3afb57b7dc42d526d4943c1b4fb60abc04a839f29ef476e57192
# 这里的token有效期24小时,一旦过期就要重新创建
kubeadm token create
kubeadm token list
# 查看集群节点,这是节点not ready 因为pod网络不能连通
kubectl get nodes
# 在master安装网络插件,集群连通
wget [https://docs.projectcalico.org/manifests/calico.yaml](https://docs.projectcalico.org/manifests/calico.yaml)
# 下载完后还需要修改里面定义Pod网络(CALICO_IPV4POOL_CIDR),与前面kubeadm init指定Pod网络的一样
# 修改完后应用清单:
kubectl apply -f calico.yaml
kubectl get pods -n kube-system
# 7. 测试kubernetes集群
# 创建pod
kubectl create deployment nginx --image=nginx
# 创建service port集群内部访问,target-port容器内部端口,NodePort外部端口随机生成
kubectl expose deployment nginx --port=80 --target-port=80 --type=NodePort
# 查看pod,sevice
kubectl get pod,svc,deployment,namespace
部署java应用
创建docker镜像
参考:https://www.jianshu.com/p/c6c56194252e控制管理器pod
kubectl create deployment k8sdemo --image k8sdemo:1.0 --dry-run -o yaml > k8sdemo.yml 输出yaml文件,不生产pod资源
kubectl apply -f k8sdemo.yml 执行yaml文件,生产pod资源,这时是不能对外访问的
- 暴露应用service
kubectl expose deployment k8sdemo --port=8080 --target-port=8080 --type=NodePort --dry-run -o yaml > k8s_svc.yml 输出yaml文件,不生产service资源
kubectl apply -f k8sdemo.yml 执行yaml文件,生产service资源,集群内部访问,外部访问
# 编辑yaml https://www.cnblogs.com/plefan/p/14149752.html
对外发布应用
日志监控
K8s的资源
Namespace对象
主要作用:用来实现多套环境的资源隔离,或者多租户下的资源隔离。
默认情况下,k8s集群中的所有pod都是可以相互访问的,因为都属于同一个namespace= default。但实际上可能需要pod之间的相互隔离。
Pod对象
为什么有?
1.K8s中最小部署单元
2.一个容器或多个容器的集合
3.Pod中的容器,网络命名空间(socket/127.0.0.1本地连接)与存储是共享的
docker 容器,一个容器只运行一个应用程序进程。pod容器,一个容器可以运行多个应用程序进程。只要为比较亲密的应用程序而设计,比如2个应用程序之间存在文件交互,网络通信,频繁调用等等。
网络共享
Pod底层采用docker容器,可是docker容器之间是隔离的,那么pod是怎么做到网络共享的呢?
解决:docker容器隔离底层实现采用linux的namespace资源隔离机制,让每个docker容器都有自己的ip,port,mac等。
而每个pod容器则是默认创建一个pause容器,将业务容器都加入到这个默认容器中 (docker的一种网络:–net=container),这样所有容器都在同一个namespace下,所有容器都享有相同的ip,port,mac等。
参考:https://network.51cto.com/art/202007/620287.htm?mobile
存储共享
数据卷
比如pod在A机器上部署,突然宕掉了,k8s在B机器上拉起了一个,那么之前的数据可定就丢失了,这个肯定是不对的。
将pod中的数据远程存储在某个地方,即挂载。
Pod容器间的数据卷挂载,2个容器挂载相同数据目录。
几种数据卷
- emptydir :Pod容器内部数据卷,共享容器内部文件,pod被删除数据卷也会被删除。主要用于某些应用程序无需永久保存的临时目录,多个docker容器的共享目录等。
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: k8sdemo
name: k8sdemo
spec:
replicas: 1
selector:
matchLabels:
app: k8sdemo
template:
metadata:
labels:
app: k8sdemo
spec:
containers:
- image: k8sdemo:1.0
name: k8sdemo
volumeMounts:
- mountPath: /mycachedata
name: mycache
- image: nginx
name: nginx
volumeMounts:
- mountPath: /mycachedata
name: mycache
volumes:
- name: mycache
# pod内容器数据共享,pod删除数据删除
emptyDir: {}
- hostPath: 机器节点上数据卷,共享host机器上文件
spec:
containers:
- image: k8sdemo:1.0
name: k8sdemo
volumeMounts:
# 指定在容器中挂接路径
- mountPath: /myhostdata
name: myhostcache
- image: nginx
name: nginx
volumeMounts:
- mountPath: /myhostdata
name: myhostcache
volumes:
- name: myhostcache
# 主机上共享数据卷,pod删除数据不删除;
# 主机宕机,数据丢失/pod被其他主机拉起,数据丢失
hostPath:
# 动作节点上目录必须存在,否则报错
path: /home/k8sdir/demo/myhostdata
- nfs : 远程存储数据卷,共享远程集群的文件。在YAML文件指定使用名称为nfs的PersistenVolumeClaim对容器的数据进行持久化。
volumes:
- name: mynfs
nfs:
path: /xxx
server: 0.0.0.0
#指定使用PersistenVolumeClaim对容器的数据进行持久化。
persistentVolumeClaim:
claimName: xxx
- Secret :加密数据卷
volumes:
- name: mysecret
secret:
secretName: set
参考链接:https://www.cnblogs.com/hongdada/p/11586514.html
Deployment控制器
K8s的控制器之一,管理pod对象,主要部署无状态应用,比如web、api等。
Pod Yaml文件中指定控制器,并为pod贴上标签,同时指定控制器要找的pod的标签。
Pod与controller的关系
Controller,又叫workload,主要是管理和运行集群上的pod容器对象,可以实现容器的动态扩缩容,回滚等
最常用的Deployment的功能与应用场景
1.部署无状态应用
2.管理pod和replicaSet
3.上线部署,副本数量,滚动更新,回滚等
应用场景:web服务,微服务等http服务
Yaml解析
使用deployment部署无状态应用
kubectl create deployment web --image=nginx --dry-run -o yaml > web-pod.yaml
kubectl expose deployment web --port=80 --target-port=90 -dry-run -o yaml -type=NodePort > web-sev.yaml
升级与回滚
本质上还是重新部署一个新的镜像,或者回滚到之前的镜像,这里相当于只是修改pod容器的镜像资源,不能直接修改service。一般service只是用来暴露应用的,基本不动。
升级
动态滚动升级镜像,会创建一个容器,当这个容器运行状态,就会删除原有的容器
kubectl set image deployment web nginx=nginx:1.15.0
直接在线编辑,保存之后直接应用
kubectl edit deployment web(pod) / kubectl edit svc web(service)
回滚
# 查看历史记录
kubectl rollout history deployment web
# 回滚
kubectl rollout undo deployment web 回滚到上一个版本
kubectl rollout undo deployment web --to-revision=1 回滚指定版本
删除
# 不能直接删除pod,因为指定副本后k8s会自动拉起一个
kubectl delete deployment web
kubectl delete svc web
弹性伸缩
扩容
# 只是扩展集群的pod容器数量,不是扩展集群中的机器数量
kubectl scale deployment web --replicas=5
金丝雀发布
比如:有一批pod需要更新,但在更新极少部分时把它暂停住,这样有一小部分是新的pod,有大多数是旧的pod。可以一小部分请求去了新的版本,其他请求还在旧的版本。如果新的版本出现了问题,就立即回滚,如果没有问题就继续全部更新。就是金丝雀发布,先极小部分更新,后全部更新或者回滚。
命令
###### 暂停发布
kubectl set image deploy myapp-deploy myapp=ikubernetes/myapp:v2 && kubectl rollout pause deploy myapp-deploy
###### 继续发布
kubectl rollout resume deploy myapp-deploy
这是新旧版本一起进行工作,,比如原先有10个pod。新的2个,旧的应该是8个。根据这个原理可以实现灰度发布,蓝绿发布。。
灰度2种方式
spec.strategy灰度发布:https://cloud.tencent.com/developer/article/1644128
Ingress-nginx转发请求:https://www.freesion.com/article/62471221222/
Service对象
为什么有?
k8s部署一个服务,会有多个pod提供服务,根据调度策略分布在不同的机器节点上。
参考:https://www.cnblogs.com/peng-zone/p/11739433.html
Pod分布在不同的机器上,通过service进行均衡请求,定位机器。
Service的功能
1,能够动态感知集群中的pod数量,ip,端口等
2,负载均衡
3,提供暴露规则,访问pod:clusterIp集群中,nodeport外部应用,localbalancer负载均衡
Service怎么与pod关联?
依旧是通过标签,获取一组pod
3种暴露应用类型
- clusterIp:集群内部产生ip,监听端口,负载均衡内部请
- Nodeport:主机节点暴露端口,外部访问
- Loadbalancer:主要为公有云预留,负载均衡做一个集成
Service怎么实现负载均衡
内部维护一张iptables路由转发规则,由LVS(ipvs)负载均衡,大并发下快速转发请求。这里集群任何一个节点service都可以转发,这里需要打通pod之间的网络连通,pod与机器节点的网络连通。
Ingress
参考链接:https://www.cnblogs.com/linuxk/p/9706720.html
Service暴露服务给外部访问,NodePort、loadBalancer。Nodeport则是是将集群内部的服务,监听一个端口,进而供外部访问,浪费集群机器的端口;loadbalancer则是需要一个外部的LB设备支持,过于麻烦。
Ingress,对象资源。只需要一个nodeport或loadbalancer,访问多个service,来解决这种痛点。 底层实现就是通过nginx,进行反向代理,创建不同的域名规则,映射到不同的service。
Ingress Controller,资源控制器。监听并解析ingress定义的规则,并转发请求到具体service。
- 环境安装,部署nginx ingress controller(nginx)
参考:https://www.cnblogs.com/panwenbin-logs/p/9915927.html
注意:
a. mantory.yml 地址:https://raw.githubusercontent.com/kubernetes/ingress-nginx/nginx-0.20.0/deploy/mandatory.yaml
b. 复制到idea中修改报错地方为apps/v1
c. 之后按照文档中来做就可以了。
- 创建ingress规则
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: ingress-rule
annotations:
kubernetes.io/ingress.class: "nginx"
spec:
rules:
- host: www.123.cn
http:
paths:
- backend:
serviceName: k8sdemo
servicePort: 8080
- hosts中配置www.123.cn映射,之后请求 http://www.123.cn:32080/hello,32080是nginx的http端口。之后的service type=clusterip,只集群内部访问,在ingress-rule中设置相对映射就可以了。
以上k8s入门基本完成,一个服务一个服务的部署,已经可以搭建项目了,可以试着做一个自己的项目。。参考实战篇:springboot项目
高级篇
界面管理
Dashboard
- 下载文件
wget https://raw.githubusercontent.com/kubernetes/dashboard/v2.0.3/aio/deploy/recommended.yaml
- 修改文件
kind: Service
apiVersion: v1
metadata:
labels:
k8s-app: kubernetes-dashboard
name: kubernetes-dashboard
namespace: kubernetes-dashboard
spec:
ports:
- port: 443
targetPort: 8443
nodePort: 30001
selector:
k8s-app: kubernetes-dashboard
type: NodePort
- 创建应用
$ kubectl apply -f recommended.yaml
$ kubectl get pods -n kubernetes-dashboard
- 访问地址:https://NodeIP:30001
# 创建用户
$ kubectl create serviceaccount dashboard-admin -n kube-system
# 用户授权
$ kubectl create clusterrolebinding dashboard-admin --clusterrole=cluster-admin --serviceaccount=kube-system:dashboard-admin
# 获取用户Token
$ kubectl describe secrets -n kube-system $(kubectl -n kube-system get secret | awk '/dashboard-admin/{print $1}')
Rancher
参考:https://blog.csdn.net/cdy2143/article/details/109534036
Master高可用
多服务部署
实战篇
springboot项目
环境:Springweb + mysql
mysql.yml
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: mydb
name: mydb
spec:
replicas: 1
selector:
matchLabels:
app: mydb
template:
metadata:
labels:
app: mydb
spec:
# 指定节点部署pod:https://blog.csdn.net/anqixiang/article/details/114151517
nodeSelector:
nodetype: "db"
# nodeName: "k8swork01"
containers:
- image: mysql:5.7
name: mysql
imagePullPolicy: IfNotPresent
volumeMounts:
- mountPath: /var/lib/mysql
name: dbdata
- mountPath: /etc/mysql/conf.d
name: dbconf
env:
- name: "MYSQL_ROOT_PASSWORD"
value: "111111"
ports:
- containerPort: 3306
volumes:
- name: dbdata
hostPath:
path: /home/k8sdir/mysql/data
- name: dbconf
hostPath:
path: /home/k8sdir/mysql/conf
---
apiVersion: v1
kind: Service
metadata:
labels:
app: mydb
name: mydb
spec:
ports:
- port: 3306
protocol: TCP
targetPort: 3306
nodePort: 30306
selector:
app: mydb
type: NodePort
demo.yml
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: k8sdemo
name: k8sdemo
spec:
replicas: 1
selector:
matchLabels:
app: k8sdemo
strategy: {}
template:
metadata:
labels:
app: k8sdemo
spec:
nodeName: "k8smaster"
containers:
- image: k8sdemo:3.0
name: k8sdemo
imagePullPolicy: IfNotPresent
ports:
- containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
labels:
app: k8sdemo
name: k8sdemo
spec:
ports:
- port: 8080
protocol: TCP
targetPort: 8080
nodePort: 30080
selector:
app: k8sdemo
type: NodePort
application.yml
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
# mydb是service名称,3306是service的端口
url: jdbc:mysql://mydb:3306/k8s_db
username: root
password: 111111