中文说明文档
https://www.yuque.com/leifengyang/oncloud/ghnb83
官方文档
https://kubernetes.io/zh/docs/setup/
集群部署
需要至少两台服务器,每台服务器都需要装上docker
可查看我的另外一篇博客:
Docker原理说明及使用+idea使用docker插件一键部署
前置环境
一台兼容的 Linux 主机。Kubernetes 项目为基于 Debian 和 Red Hat 的 Linux 发行版以及一些不提供包管理器的发行版提供通用的指令
每台机器 2 GB 或更多的 RAM (如果少于这个数字将会影响你应用的运行内存)
2 CPU 核或更多
集群中的所有机器的网络彼此均能相互连接(公网和内网都可以)
设置防火墙放行规则
节点之中不可以有重复的主机名、MAC 地址或 product_uuid。请参见这里了解更多详细信息。
设置不同hostname
开启机器上的某些端口。请参见这里 了解更多详细信息。
内网互信(设置专有网络vpc)
禁用交换分区。为了保证 kubelet 正常工作,你 必须 禁用交换分区。
永久关闭
所有机器执行以下操作
各个机器设置自己的域名(主机名)
hostnamectl set-hostname xxxx
将 SELinux 设置为 permissive 模式(相当于将其禁用)
临时禁用:sudo setenforce 0永久禁用:sudo sed -i 's/^SELINUX=enforcing$/SELINUX=permissive/' /etc/selinux/config
关闭swap
临时关闭Swap分区:swapoff -a 永久关闭Swap分区:sed -ri 's/.*swap.*/#&/' /etc/fstab
允许 iptables 检查桥接流量
cat <<EOF | sudo tee /etc/modules-load.d/k8s.confbr_netfilterEOF
cat <<EOF | sudo tee /etc/sysctl.d/k8s.confnet.bridge.bridge-nf-call-ip6tables = 1net.bridge.bridge-nf-call-iptables = 1EOF
让以上配置生效
sudo sysctl --system
安装kubelet、kubeadm、kubectl
指定kubernetes.repo下载地址以及阿里云镜像
cat <<EOF | sudo tee /etc/yum.repos.d/kubernetes.repo[kubernetes]name=Kubernetesbaseurl=http://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64enabled=1gpgcheck=0repo_gpgcheck=0gpgkey=http://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg http://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpgexclude=kubelet kubeadm kubectlEOF
安装
sudo yum install -y kubelet-1.20.9 kubeadm-1.20.9 kubectl-1.20.9 --disableexcludes=kubernetes
启动kubelet
sudo systemctl enable --now kubelet
下载各个机器需要的镜像
下载镜像
sudo tee ./images.sh <<-'EOF'#!/bin/bashimages=(kube-apiserver:v1.20.9kube-proxy:v1.20.9kube-controller-manager:v1.20.9kube-scheduler:v1.20.9coredns:1.7.0etcd:3.4.13-0pause:3.2)for imageName in ${images[@]} ; dodocker pull registry.cn-hangzhou.aliyuncs.com/lfy_k8s_images/$imageNamedoneEOF
赋权并启动
chmod +x ./images.sh && ./images.sh
初始化节点
找到需要设置k8s-master的服务器
所有机器添加master域名映射,以下需要修改为自己的专有vpc
echo "172.16.217.1 cluster-endpoint" >> /etc/hosts
如果所有机器上都能 ping cluster-endpoint 就说明kubeadm join成功
主节点初始化(只在master上运行)
kubeadm init \--apiserver-advertise-address=172.16.217.1 \--control-plane-endpoint=cluster-endpoint \--image-repository registry.cn-hangzhou.aliyuncs.com/lfy_k8s_images \--kubernetes-version v1.20.9 \--service-cidr=10.96.0.0/16 \--pod-network-cidr=192.168.0.0/16
说明:所有网络范围不重叠这里是k8s内部的网段,且不能与服务器设置的专有网络重叠
–service-cidr=10.96.0.0/16
–pod-network-cidr=192.168.0.0/16
下面这里最好全部复制出来,后面有用到
查看集群所有节点(在master节点中运行)
kubectl get nodes
我们会发现这里显示的是notready 没有部署网络插件
安装网络组件(在master节点中运行)
curl https://docs.projectcalico.org/manifests/calico.yaml -O
根据配置文件,给集群创建资源
kubectl apply -f calico.yaml
注:如果这里在之前主节点初始化时修改了
–pod-network-cidr=192.168.0.0/16
那么就需要你重新修改
在node机器上运行令牌 (24小时内有效之前保存的)
如果这个令牌过期或者丢失了那么在master上使用命令重新生成新的令牌
kubeadm token create --print-join-command
查看k8s集群部署了那些应用
kubectl get pods -A #运行中的应用在docker里面叫容器,在k8s里面叫Podkubectl get pods -A -w #实时监控运行状态 -w 监视资源变动信息watch -n 1 kubectl get pods -A #每秒自动刷新查询状态
部署dashboard可视化界面(以下所有命令执行均在master节点)
kubernetes官方提供的可视化界面
https://github.com/kubernetes/dashboard
kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.3.1/aio/deploy/recommended.yaml
修改配置dashboard 文件信息
kubectl edit svc kubernetes-dashboard -n kubernetes-dashboardtype: ClusterIP 改为 type: NodePort
找到端口,在安全组放行
访问: https://集群任意IP(master或node):端口
创建访问权限并通过token访问
准备一个yaml文件; vi dash.yaml
dash.yaml
apiVersion: v1kind: ServiceAccountmetadata: name: admin-user namespace: kubernetes-dashboard---apiVersion: rbac.authorization.k8s.io/v1kind: ClusterRoleBindingmetadata: name: admin-userroleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: cluster-adminsubjects:- kind: ServiceAccount name: admin-user namespace: kubernetes-dashboard
使yaml文件在k8s中生效
kubectl apply -f dash.yaml
获取访问令牌(这里一定要注意中括号后面的不要复制了)
kubectl -n kubernetes-dashboard get secret $(kubectl -n kubernetes-dashboard get sa/admin-user -o jsonpath="{.secrets[0].name}") -o go-template="{{.data.token | base64decode}}"
K8S中的NameSpace
获取k8s的名称空间(NameSpace)
kubectl get namespace 或者 kubectl get ns
获取名称空间(NameSpace)下的应用
kubectl get pod -n NameSpace名称
创建/删除自定义名称空间(NameSpace)
kubectl create ns xxxxx
kubectl delete ns xxxxx (删除名称空间会将该空间下的资源连带删除)
Pod
pod:运行中的一组容器,Pod是kubernetes中应用的最小单位.
查看k8s集群部署了那些应用:
kubectl get pod -A
这里的pod 就是指的k8s中的容器
创建容器镜像(默认创建在defaul命名空间中):
kubectl run mynginx --image=nginx
mynginx:表示应用名称唯一且不能重复
–image=nginx:–image=镜像名称可以指定版本号如–image=nginx:1.21.0,不指定则表示默认最新版本
指定命名空间:
kubectl run mynginx --image=nginx -n 自定义命名空间名称
查看名称空间的Pod
kubectl get pod #默认查看default名称空间的Podkubectl get pod -n 指定命名空间 #查看指定名称空间的Pod
查看描述信息
kubectl describe pod mynginx(你自己的Pod名字)
删除pod
kubectl delete pod Pod名字
如果删除的不是default空间下的pod 需要加上空间名称删除 如:
kubectl delete pod Pod名字 -n 空间名称
查看Pod的运行日志
kubectl logs Pod名字-n 指定命名空间名
每个Pod – k8s都会分配一个ip
kubectl get pod -owide
集群中的任意一个机器以及任意的应用都能通过Pod分配的ip来访问这个Pod
自己下载的镜像分配的ip为192.168.xxx.xxx,这里分配的192.168网段是我们在安装k8s时设置的网段
以yaml文件的形式创建Pod及镜像
1、结合dashboard可视化面板对pod进行创建
创建yaml脚本
apiVersion: v1kind: Podmetadata: labels: run: mynginx name: mynginx# namespace: defaultspec: containers: - image: nginx name: mynginx
还可yaml中选择放在哪一个空间下,不需要手动选择空间
一个pod容器中可创建多个镜像
创建yaml脚本
apiVersion: v1kind: Podmetadata: labels: run: myapp name: myappspec: containers: - image: nginx name: nginx - image: tomcat:8.5.68 name: tomcat
注:这里创建多个镜像时不能创建两个相同port的镜像在同一个端口,比如这里弄两个nginx
创建完成后这里的pod会分配一个内网ip
集群内访问只需要查询出上方创建的myapp的内网ip
kubectl get pod -n 空间名称 -owide
如显示的是192.168.47.12
所有集群内网访问nginx只需要在服务器中
curl 192.168.47.12 (80端口默认)
所有集群内网访问tomcat只需要在服务器中
curl 192.168.47.12:8080
如果在pod内nginx需要访问tomcat那么只需要
127.0.0.1:8080
此时的应用还不能外部访问
2、Linux创建pod容器
首先创建一个yaml文件:
vi xxxx.yaml
粘贴yaml脚本并保存
apiVersion: v1kind: Podmetadata: labels: run: myapp name: myappspec: containers: - image: nginx name: nginx - image: tomcat:8.5.68 name: tomcat
将文件应用到k8s:
Kubectl apply -f xxxx.yaml
删除pod:
找到xxxx.yaml位置并执行命令
Kubectl delete -f xxxx.yaml
也可使用:kubectl delete pod Pod名字
但是这样xxxx.yaml
文件并没有被删除
Deployment
控制Pod,使Pod拥有多副本,自愈,扩缩容等能力
正常情况下我们使用kubectl
命令创建nginx镜像,如果使用
kubectl delete pod Pod名字
pod是真正的完整的被删除,如果使用deployment 创建镜像,那么如果删除的话每次删除都会自动在其他集群再次创建一个,自愈能力
deployment创建pod
这里我没有指定命名空间自动创建在default中
kubectl create deployment mytomcat --image=tomcat:8.5.68
删除使用deployment创建的pod
kubectl delete deployment --all
-n:如果是非default需要指定命名空间,省略则默认为default空间
创建指定数量的Deployment
kubectl create deployment my-dep --image=nginx --replicas=3
yaml脚本创建
apiVersion: apps/v1kind: Deploymentmetadata: labels: app: my-dep name: my-depspec: replicas: 3 selector: matchLabels: app: my-dep template: metadata: labels: app: my-dep spec: containers: - image: nginx name: nginx
Dashboard可视化界面创建
deployment的扩缩容三种方式
前提是容器正常运行才可进行扩缩容操作
1、命令形式
将其扩容/缩容到5个
kubectl scale --replicas=5 deployment/my-dep
2、修改yaml形式
kubectl edit deployment my-dep
3、dashboard可视化界面
Deployment自愈&故障转移说明
1、停止镜像运行(自愈)
如果我们的nginx镜像时部署在node1机器上那么我们在node1机器上使用命令
docker ps #查询所有运行的镜像docker stop 容器id #停止当前镜像运行
停机(停机之后自愈能力是指停机后Deploy会让这个停机的容器又尝试重启)
2、服务器关机(故障转移)
服务器关机后大概有5分钟的时间检测,5分钟后会在其他机器上自启
删除pod、容器宕机(现在有master、node1、node2,如果node1机器直接宕机了,经过一段时间,原来在node1上的pod会转移到node2节点上)
滚动更新(不停机更新)
当kubernetes集群中的某个服务需要升级时,传统的做法是,先将要更新的服务下线,业务停止后再更新版本和配置,然后重新启动并提供服务。如果业务集群规模较大时,这个工作就变成了一个挑战,而且先全部了停止,再逐步升级的方式会导致服务较长时间不可用。kubernetes提供了滚动更新(rolling-update)的方式来解决上述问题。
简单来说,滚动更新就是针对多实例服务的一种不中断服务的更新升级方式。一般情况下,对于多实例服务,滚动更新采用对各个实例逐个进行单独更新而非同一时刻对所有实例进行全部更新的方式。
滚动更新是一次只更新一小部分副本,成功后,再更新更多的副本,最终完成所有副本的更新。滚动更新的最大的好处是零停机,整个更新过程始终有副本在运行,从而保证了业务的连续性。
如需要对某个镜像进行升级那么可以使用命令
如原本的nginx镜像在default命名空间,nginx版本为1.21.0,先需要将版本更改为1.22.1
kubectl set image deployment/my-dep nginx=nginx:1.22.1 --record
–record:版本记录
非default命名空间需要加上 -n 空间名
执行命令后我们会发现,k8s会新创建一个nginx镜像等待状态为running然后逐个删除掉之前的镜像,直到deployment创建的所有镜像全部逐个更新
状态
kubectl rollout status deployment/my-dep
修改配置文件的方式达到版本更新
kubectl edit deployment/my-dep
版本回退
查看安装的历史版本
kubectl rollout history deployment/my-dep
非default空间需要加上 -n空间名称
查看升级记录的历史详情
kubectl rollout history deployment/my-dep --revision=2
如果是安装的记录则 –revision=1
回滚(回到上次)
kubectl rollout undo deployment/my-dep
回滚(回到指定版本)
kubectl rollout undo deployment/my-dep --to-revision=2
如果是回滚到安装的记录则 –revision=1
除了Deployment,k8s还有 StatefulSet 、DaemonSet 、Job 等 类型资源。我们都称为 工作负载。
有状态应用使用 StatefulSet 部署,无状态应用使用 Deployment 部署
https://kubernetes.io/zh/docs/concepts/workloads/controllers/
Service(集群内访问以及外部访问)
Service:Pod集群的统一访问路口
ClusterIP(集群内部访问)
将一组 Pods 公开为网络服务的抽象方法。Pod的服务发现和负载均衡
如果default命名空间中使用deplotment创建了3个nginx的副本,这时候每个副本k8s都会生成一个内网ip,如果想访问其中的某一个nginx就需要使用 内网ip:端口号
其中如果有一个pod挂掉了这时候的nginx是访问不了的,这时候想访问另外一个pod就需要更改访问的ip,这里的service就能通过服务发现实现负载均衡
暴露deployment (将一组pod暴露成一个端口)
kubectl expose deployment my-dep --port=8000 --target-port=80 --type=ClusterIP
8000:需要对外暴露的统一端口
80:负载均衡中的机器所占用的端口
–type=ClusterIP:可省略,默认 代表集群内可访问的ip
注:这里节点访问可通过ip:端口,如果是在pod容器内访问可通过域名访问:
域名规则:服务名.空间名.svc:端口 (my-dep.default.svc:8000
)
查询暴露的service
kubectl get service(svc也可) #默认default命名空间下的service-A:查询所有的service
使用标签检索Pod
查询pod的标签
kubectl get pod --show-labels
kubectl get pod -l app=my-dep
-l 标签选择器(多个的话是与逻辑)
NodePort(外网端口访问)
暴露deployment (将一组pod暴露成一个端口)
kubectl expose deployment my-dep --port=8000 --target-port=80 --type=NodePort
my-dep:需要暴露的pod前缀
–port=8000:需要暴露的端口
–target-port=80:负载均衡中的机器所占用的端口
这里和ClusterIP 创建的service不同会多出来一个port
30948是k8s分配的一个端口(NodePort范围在 30000-32767 之间)30948端口会在每一台集群上都开一个这样的端口(端口需自行前往服务器安全中配置
)
公网访问ip:集群内任意一台机器公网ip:端口
删除创建的service
kubectl delete svc xxxx(服务名如my-dep)
Ingress
官网地址:https://kubernetes.github.io/ingress-nginx/
就是nginx做的
Service的统一网关入口
安装
wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v0.47.0/deploy/static/provider/baremetal/deploy.yaml
修改镜像
vi deploy.yaml
将image的值改为阿里云镜像如下
registry.cn-hangzhou.aliyuncs.com/lfy_k8s_images/ingress-nginx-controller:v0.46.0
将其应用到k8s
kubectl apply -f deploy.yaml
等待他状态全部为Running即可
也可使用命令检查安装的结果
kubectl get pod,svc -n ingress-nginx
这里k8s会自动创建两个NodePort端口,一个为http,一个为https分别配置了端口号,这里的端口号在服务器上的安全组中放行即可在外部访问
http://集群内任何一个服务器公网ip:http端口号
https://集群内任何一个服务器公网ip:https端口号
将service配置到Ingress
配置文件配置
vi xxxx.yaml
apiVersion: networking.k8s.io/v1kind: Ingress metadata: name: ingress-host-barspec: ingressClassName: nginx rules: - host: "hello.atguigu.com" http: paths: - pathType: Prefix path: "/" backend: service: name: hello-server port: number: 8000 - host: "demo.atguigu.com" http: paths: - pathType: Prefix path: "/nginx" backend: service: name: nginx-demo port: number: 8000
kubectl apply -f xxxx.yaml
路径重写
apiVersion: networking.k8s.io/v1kind: Ingress metadata: annotations: nginx.ingress.kubernetes.io/rewrite-target: /$2 name: ingress-host-barspec: ingressClassName: nginx rules: - host: "hello.atguigu.com" http: paths: - pathType: Prefix path: "/" backend: service: name: hello-server port: number: 8000 - host: "demo.atguigu.com" http: paths: - pathType: Prefix path: "/nginx(/|$)(.*)" backend: service: name: nginx-demo port: number: 8000
流量限制
apiVersion: networking.k8s.io/v1kind: Ingressmetadata: name: ingress-limit-rate annotations: nginx.ingress.kubernetes.io/limit-rps: "1"spec: ingressClassName: nginx rules: - host: "haha.atguigu.com" http: paths: - pathType: Exact path: "/" backend: service: name: nginx-demo port: number: 8000
Service总结模型
K8s存储抽象
相当于之前pod上安装的软件,进行文件外部挂载,但是每个pod都挂载,当pod出现问题,外部挂载文件无法同步,可能就会丢失数据,使用一个外部统一的文件处理系统,使用文件系统的高可用来完善文件的挂载
所有机器安装
yum install -y nfs-utils
nfs主节点
echo "/nfs/data/ *(insecure,rw,sync,no_root_squash)" > /etc/exports
创建/nfs/data文件夹(主节点)
mkdir -p /nfs/data
启动rpc远程绑定(主节点)
systemctl enable rpcbind --now
(开机)启动nfs服务(主节点)
systemctl enable nfs-server --now
配置生效(主节点)
exportfs -r
查看主节点机器有哪些目录可以同步挂载(node节点)
showmount -e 主节点的内网ip
执行以下命令挂载 nfs 服务器上的共享目录到本机路径(node节点)
mkdir -p /nfs/datamount -t nfs 172.31.0.4:/nfs/data /nfs/data
172.31.0.4:主节点的内网ip /nfs/data:这里为你从节点服务器的路径,如从节点服务器创建了一个路径
mkdir -p /abc/nfs
mount -t nfs 172.31.0.4:
/nfs/data /abc/nfs
如现在的服务器是k8s-node1 在服务器下创建一个文件夹/abc/nfs,使用命令:
mount -t
同步主节点内网ip下的/nfs/data nfs路径同步到k8s-node1 下的/abc/nfs下
写入一个测试文件
echo "hello nfs server" > /nfs/data/test.txt
在任何一台机器对同步的文件下的内容有改动那么,所有机器下的改文件下的内容都会进行改动
原生方式数据挂载
apiVersion: apps/v1kind: Deploymentmetadata: labels: app: nginx-pv-demo name: nginx-pv-demospec: replicas: 2 selector: matchLabels: app: nginx-pv-demo template: metadata: labels: app: nginx-pv-demo spec: containers: - image: nginx name: nginx volumeMounts: - name: html mountPath: /usr/share/nginx/html volumes: - name: html nfs: server: 172.31.0.4 path: /nfs/data/nginx-pv
PV&PVC
PV:持久卷(Persistent Volume),将应用需要持久化的数据保存到指定位置
PVC:持久卷申明(Persistent Volume Claim),申明需要使用的持久卷规格
创建pv池
静态供应
#nfs主节点
mkdir -p /nfs/data/01
mkdir -p /nfs/data/02
mkdir -p /nfs/data/03
创建PV
apiVersion: v1kind: PersistentVolumemetadata: name: pv01-10mspec: capacity: storage: 10M accessModes: - ReadWriteMany storageClassName: nfs nfs: path: /nfs/data/01 server: 172.31.0.4---apiVersion: v1kind: PersistentVolumemetadata: name: pv02-1gispec: capacity: storage: 1Gi accessModes: - ReadWriteMany storageClassName: nfs nfs: path: /nfs/data/02 server: 172.31.0.4---apiVersion: v1kind: PersistentVolumemetadata: name: pv03-3gispec: capacity: storage: 3Gi accessModes: - ReadWriteMany storageClassName: nfs nfs: path: /nfs/data/03 server: 172.31.0.4
PVC创建与绑定
创建PVC
kind: PersistentVolumeClaimapiVersion: v1metadata: name: nginx-pvcspec: accessModes: - ReadWriteMany resources: requests: storage: 200Mi storageClassName: nfs
创建Pod绑定PVC
apiVersion: apps/v1kind: Deploymentmetadata: labels: app: nginx-deploy-pvc name: nginx-deploy-pvcspec: replicas: 2 selector: matchLabels: app: nginx-deploy-pvc template: metadata: labels: app: nginx-deploy-pvc spec: containers: - image: nginx name: nginx volumeMounts: - name: html mountPath: /usr/share/nginx/html volumes: - name: html persistentVolumeClaim: claimName: nginx-pvc
ConfigMap
抽取应用配置,并且可以自动更新
redis示例
把之前的配置文件创建为配置集
创建配置,redis保存到k8s的etcd;
vi redis.confkubectl create cm redis-conf --from-file=redis.conf
当配置集创建完成后即可删除redis.conf 主要作用就是为了创建配置集
查看配置集yaml内容
关键内容:
apiVersion: v1
data: #data是所有真正的数据,key:默认是文件名 value:配置文件的内容
redis.conf: |
appendonly yes
kind: ConfigMap #资源类型ConfigMap
metadata:
name: redis-conf #资源名称
namespace: default
创建Pod
apiVersion: v1kind: Podmetadata: name: redisspec: containers: - name: redis image: redis command: - redis-server - "/redis-master/redis.conf" #指的是redis容器内部的位置 ports: - containerPort: 6379 volumeMounts: - mountPath: /data name: data - mountPath: /redis-master name: config volumes: - name: data emptyDir: {} - name: config configMap: name: redis-conf items: - key: redis.conf path: redis.conf
检查默认配置
kubectl exec -it redis -- redis-cli
127.0.0.1:6379> CONFIG GET appendonly127.0.0.1:6379> CONFIG GET requirepass
修改ConfigMap
apiVersion: v1kind: ConfigMapmetadata: name: example-redis-configdata: redis-config: | maxmemory 2mb maxmemory-policy allkeys-lru
检查配置是否更新
kubectl exec -it redis -- redis-cli
127.0.0.1:6379> CONFIG GET maxmemory127.0.0.1:6379> CONFIG GET maxmemory-policy
检查指定文件内容是否已经更新
修改了CM。Pod里面的配置文件会跟着变
配置值未更改,因为需要重新启动 Pod 才能从关联的 ConfigMap 中获取更新的值。
原因:我们的Pod部署的中间件自己本身没有热更新能力
Secret
Secret 对象类型用来保存敏感信息,例如密码、OAuth 令牌和 SSH 密钥。 将这些信息放在 secret 中比放在 Pod 的定义或者 容器镜像 中来说更加安全和灵活。
kubectl create secret docker-registry leifengyang-docker
–docker-username=leifengyang
–docker-password=Lfy123456
–docker-email=534096094@qq.com
命令格式
kubectl create secret docker-registry regcred
–docker-server=
–docker-username=
–docker-password=
–docker-email=
apiVersion: v1kind: Podmetadata: name: private-nginxspec: containers: - name: private-nginx image: leifengyang/guignginx:v1.0 imagePullSecrets: - name: leifengyang-docker