1. 基础

本文实操基于k8s 1.22.1

# 可以查看资源分配情况
kubectl describe node
# 全局资源情况查看
kubectl api-resources

1.1 apply

apply 命令可以使用配置文件创建资源

  • -f 使用yaml或json创建资源, 也是比较常用的方式
kubectl apply -f ./my1.yaml                   # 创建资源
kubectl apply -f ./my1.yaml -f ./my2.yaml # 使用多个文件创建
kubectl apply -f ./dir # 基于目录下的所有清单文件创建资源
kubectl apply -f https://git.io/vPieo # 从 URL 中创建资源

从标准输出流创建

# 从标准输入创建多个Pod
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
name: busybox-sleep
spec:
containers:
- name: busybox
image: busybox
args:
- sleep
- "1000000"
---
apiVersion: v1
kind: Pod
metadata:
name: busybox-sleep-less
spec:
containers:
- name: busybox
image: busybox
args:
- sleep
- "1000"
EOF # 创建有多个 key 的 Secret
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Secret
metadata:
name: mysecret
type: Opaque
data:
password: $(echo -n "s33msi4" | base64 -w0)
username: $(echo -n "jane" | base64 -w0)
EOF

1.2 get

列出一个或多个资源

类型 说明
pods, pod, po 列出pod信息
replicationcontroller, rc 列出副本控制器
services, svc 列出服务
ds 列出守护程序集
参数 默认值 说明
-A, --all-namespace false 返回所有命名空间的资源, 即使指定-n也无效
--chunk-size 500 以块的形式返回大列表,而不是一次返回所有列表。传递0以禁用。
--ignore-not-found false true: 查找不到资源时不报错
-o, --output '' json,yaml,name,go-template,go-template-file,template,templatefile,jsonpath,jsonpath-as-json,jsonpath-file,custom-columns-file,custom-columns,wide

yaml: 以yaml格式输出详细配置
wide: 以列表输出较详细的信息
name: 仅打印资源名称
json: 以json格式输出详细信息
--server-print true 是否打印从服务器接收的特定列信息, 比如: STATUS(运行状态), RESTARTS(重启次数)
--show-labels false 查看对应资源设置的标签
--sort-by '' 接受 jsonpath 表达式, 比如按名称排序的pod列表 kubectl get pods --sort-by=.metadata.name
--template ''
-w, --watch false 监控资源变化, 开启一个常驻任务, 可使用pod name监控单个pod
-n, --namespace 命名空间

1.3 describe

显示一个或多个资源的详细状态,默认情况下包括未初始化的资源。

2. 依赖

2.1 命名空间 namespace

  • namespace的写法: namespaces, namespace, ns

将资源归类, 相关的服务放在同一个命名空间下方便管理

# 创建命名空间
kubectl create namespace
# 查询命名空间
kubectl get ns
# 删除命名空间
kubectl delete namespace NAME
# yaml 配置
apiVersion: v1
kind: Namespace
metadata:
name: repo-nexus
labels:
name: repo-nexus

k8s集群默认拥有如下几个namespace

NAME              STATUS   AGE
default Active 2d3h
kube-node-lease Active 2d3h
kube-public Active 2d3h
kube-system Active 2d3h
  • 所有NAMESPACED的资源,在创建的时候都需要指定namespace,若不指定,默认会在default命名空间下

  • 相同namespace下的同类资源不可以重名,不同类型的资源可以重名

  • 不同namespace下的同类资源可以重名

  • 通常在项目使用的时候,我们会创建带有业务含义的namespace来做逻辑上的整合

2.2 apiVersion

apiVersion 含义
alpha 进入K8s功能的早期候选版本,可能包含Bug,最终不一定进入K8s
beta 已经过测试的版本,最终会进入K8s,但功能、对象定义可能会发生变更。
stable 可安全使用的稳定版本
v1 stable 版本之后的首个版本,包含了更多的核心对象
apps/v1 使用最广泛的版本,像Deployment、ReplicaSets都已进入该版本

资源类型与apiVersion对照表(版本不同也会不太一样, 具体以官方文档为准)

Kind apiVersion
ClusterRoleBinding rbac.authorization.k8s.io/v1
ClusterRole rbac.authorization.k8s.io/v1
ConfigMap v1
CronJob batch/v1beta1
DaemonSet extensions/v1beta1
Node v1
Namespace v1
Secret v1
PersistentVolume v1
PersistentVolumeClaim v1
Pod v1
Deployment v1、apps/v1、apps/v1beta1、apps/v1beta2
Service v1
Ingress extensions/v1beta1
ReplicaSet apps/v1、apps/v1beta2
Job batch/v1
StatefulSet apps/v1、apps/v1beta1、apps/v1beta2

快速获得资源和版本

kubectl explain pod
kubectl explain Pod.apiVersion

2.3 集群node label

# 查询node上已有的标签信息
kubectl get nodes --show-labels
# 为节点打标签
kubectl label node k8s-n-1 component=mysql

2.4 configmap

通常用来管理应用的配置文件或者环境变量, 放一些不是特别敏感的信息

apiVersion: v1
kind: ConfigMap
metadata:
name: xxxx
namespace: default
data:
# 配置 key: value
MYSQL_HOST: "172.168.23.11"
MYSQL_PORT: "3306"
kubectl create -f configmap.yaml

使用文本文件创建

MYSQL_HOST=172.168.23.11
MYSQL_PORT=3306
kubectl create configmap xxx --form-env-file=xxx.txt -n default

2.5 secret

管理敏感类信息, 默认会base64编码存储, 有三种类型

  • Service Account: 用来访问Kubernetes API, 有Kubernetes自动创建, 并且会自动挂载到Pod的/run/secrets/kubernetes.io/serviceaccount目录中; 创建ServiceAccount后, pod中指定serviceAccount后, 自动创建该ServiceAccount对应的secret
  • Opaque: base64编码格式的Secret, 用来存储密码, 密钥等;
  • kubernetes.io/dockerconfigjson: 用来存储私有docker registry的认证信息
apiVersion: v1
kind: Secret
metadata:
name: xxxx
namespace: default
type: Opaque
data:
# 配置 key: base64(value)
MYSQL_USER: cm9vdA==
MYSQL_PASSWD: MTIzNDU2
kubectl create -f configmap.yaml

使用文本文件创建, 不需要进行base64编码

MYSQL_USER=rootMYSQL_PASSWD=123456
kubectl create secret generic xxx --form-env-file=xxx.txt -n default

3. Pod

  • pod支持的写法: pods, pod, po

docker调度的是容器,在k8s集群中,最小的调度单元是Pod

  • 与容器引擎解耦 Docker、Rkt。平台设计与引擎的具体的实现解耦
  • 多容器共享网络|存储|进程 空间, 支持的业务场景更加灵活
# yamlapiVersion: v1kind: Pod  # 资源类型metadata:  # 基本配置  name: POD_NAME  namespace: MY_NS  labels:  # 给pod打标签, 方便管理, 后面用到会有介绍    component: POD_NAMEspec:  containers:  # 容器配置  - name: NAME1  # 容器名    image: IMAGE  # 镜像仓库地址    env:  # 环境变量    - name: MYSQL_HOST   #  指定root用户的用户名      value: "127.0.0.1"    - name: MYSQL_PASSWD      value: "123456"    ports:  # 容器暴漏的端口    - containerPort: 8002  - name: mysql  # 一个pod可以拥有多个容器    image: mysql    ports:    - containerPort: 3306    env:    - name: MYSQL_ROOT_PASSWORD      value: "123456"    - name: MYSQL_DATABASE      value: "myblog"
# 创建podkubectl create -f pod.yamlkubectl apply -f pod.yamlkubectl run --image=IMAGE POD_NAME # 更多kubectl run 用法参考kubeclt run -h# 可以通过试运行获取基础yaml文件kubectl run --image=nginx --dry-run -o yaml nginx# 更新服务版本kubectl apply -f pod.yaml# 查看pod, -n 指定命名空间, -o wide 显示更多信息(可以看到调度节点)kubectl get pods -o wide -n xxx# 查看pod的明细信息及事件kubectl describe pods -n xxx POD_NAME# 查看pod完整的yamlkubectl get pods -o yaml -n xxx POD_NAME# 查看Pod内容器日志,显示标准或者错误输出日志kubectl logs -n xxx -f POD_NAME -c CONTAINER_NAME# --tail限定行数, 类似于docker命令 docker logs --tail=10 -f xxxxxkubectl -n default logs -f --tail=10 nginx -c nginx# 删除容器kubectl delete -f pod.yamlkubectl delete pod -n xxx POD_NAME# 进入容器, -c 指定进入哪个容器kubectl -n xxx exec -it POD_NAME -c NAME1 bash# 使用 -o wide 我们可以看到pod在哪台机器, 那么对应的容器也就是在那台机器# 我们可以在相应机器上执行 docker ps 查看容器信息docker ps -a | grep NAME1# pod 中的容器命名格式为: k8s_<container_name>_<pod_name>_<pod_uuid>

3.1 节点选择器

  • nodeSelector 节点选择器, 可将pod调度到有某个label的node上, 如果node不存在, pod将不会正常创建, 直到node被打上相应label将会自动部署, 而不用重新创建
spec:  nodeSelector:   # 使用节点选择器将Pod调度到指定label的节点    component: mysql   # 指定选择有mysql标签的node

3.2 数据持久化

类似于docker的数据挂载, 但我们之前挂载都是在单机上进行, 现在我们在集群中使用volumes挂载其也仅会挂载在pod所在的机器上, 当我们重新上线时pod被调度到其它机器就依然会存在找不到数据的问题, 在这里我们使用nodeSelector解决, 当然生产上一般不会用这种方法

...spec:  volumes:   - name: mysql-data    hostPath:      path: /opt/mysql/data  nodeSelector:    component: mysql  containers:  - name: mysql    image: mysql    ...    volumeMounts:    - name: mysql-data      mountPath: /var/lib/mysql

使用PV+PVC连接分布式存储解决方案

  • ceph
  • glusterfs
  • nfs

3.3 服务健康检查

两种探针

  • LivenessProbe探针: 存活性探测, 用于判断容器是否存活, 即Pod是否为running状态, 如果LivenessProbe探针探测到容器不健康, 则kubelet将kill掉容器, 并根据容器的重启策略是否重启, 如果一个不包含LivenessProbe探针, 则Kubelet认为容器的LivenessProbe探针返回值永远成功
  • ReadinessProbe探针: 可用性探测, 用于探测容器是否正常提供服务, 即容器的Ready是否为True, 是否可以接收请求, 如果ReadinessProbe探测失败, 则容器的Ready将为False, Endpoint Controller控制器将此Pod的Endpoint从对应的serviceEndpoint列表中移除, 不再将任何请求调度此Pod上, 直到下次探测成功. (剔除此Pod不参与接收请求不会将流量转发给此Pod)

三种类型

  • exec: 执行一个命令, 返回状态值为0则表示容器健康

  • httpGet: 发送一个http请求, 返回200-399表示容器健康

  • tcpSocket: 通过容器的IP和Port执行TCP检查, 如果能建立连接, 则表示容器健康

参数及含义

  • initialDelaySeconds: 启动后第一次执行探测需要等待多少秒
  • perioSeconds: 执行探测的频率. 默认10秒, 最小1秒
  • timeoutSeconds: 探测超时时间. 默认1秒, 最小1秒
  • successThreshold: 探测失败后, 最少连续探测成功多少次才被认定为成功. 默认1
  • failureThreshold: 探测成功后, 最少连续探测失败多少次才被认定为失败. 默认3, 最小1
spec:  containers:  - image: xxx    name: xxx    livenessProbe:  # 指定探针, 此处也可指定 readinessProbe      # 使用http请求, 请求容器80端口来判断容器是否存活      httpGet:        path: /blog/index        port: 80        scheme: HTTP      initialDelaySeconds: 10  # 容器启动后第一次执行探测需要等待多少秒      perioSeconds: 10  # 执行探测的频率      timeoutSeconds: 2  # 探测超时时间

3.4 重启策略

Pod的重启策略(RestartPolicy)应用于Pod内所有容器, 并仅在Pod所处的Node上由kubelet进行判断和重启操作. 当某个容器异常退出或健康检查失败时, kubelet将根据RestartPolicy的设置来进行相应的操作. Pod的重启策略包括:Always、OnFailure和Never,默认值为Always

  • Always:当容器失效时(无论是否正常退出),由kubelet自动重启该容器。
  • OnFailure:当容器终止运行且退出码不为0时,由kubelet自动重启该容器。
  • Never:不论容器运行状态如何,kubelet都不会重启该容器。
spec:  restartPolicy: Always  containers:  - name: xxx    image: xxx    args:   # 模拟异常退出, 容器参数    - /bin/sh    - -c    - sleep 10 && exit 1

3.5 镜像拉取策略

spec:  containers:  - name: xxx    image: xxx    imagePullPolicy: IfNotPresent

镜像拉取策略: 默认IfNotPresent

  • Always: 总是拉取镜像, 即使本地有也从仓库拉取
  • IfNotPresent: 优先使用本地, 本地没有则去仓库拉取
  • Never: 仅使用本地镜像, 本地没有则报错

3.6 Pod资源限制

注意:若内存使用超出限制,会引发系统的OOM机制,因CPU是可压缩资源,不会引发Pod退出或重建

spec:
containers:
- name: xxx
image: xxx
resources:
requests:
memory: 100Mi
cpu: 50m
limits:
memory: 100Mi
cpu: 50m

requests:

  • 容器使用的最小资源需求, 作用与schedule阶段, 作为容器调度时资源分配的判断依赖
  • 只有当节点上可分配的资源量>=request时才允许将容器调度到该节点
  • request参数不限制容器的最大可使用资源
  • requests.cpu被转成docker的--cpu-shares参数, 与cgroup cpu.shares功能相同(无论宿主机有多少个cpu或内核, --cpu-shares选项都会按照比例分配cpu资源)
  • requests.memory没有对应的docker参数, 仅作为k8s调度依据

limits:

  • 容器能使用的资源最大量
  • 设置为0表示对使用的资源不限制, 可无限使用
  • 当pod内存超过limit时, 会被oom
  • 当cpu超过limit时, 不会被kill, 但是会限制不超过limit值
  • limits.cpu会被转为docker的-cpu-qiota参数. 与cgroup cpu.cfs_quota_us功能相同
  • limits.memory会被转成docker的-memory参数. 用来限制容器最大内存

3.7 网络

如果在POD中使用"hostNetwork: true"配置网络,pod中运行的应用程序可以直接看到宿主主机的网络接口,宿主机所在的局域网上所有网络接口都可以访问到该应用程序及端口。声明pod的网络模式为host模式,效果同docker run --net=host

spec:  hostNetwork: true

3.8 引用配置

3.8.1 引用configmap

spec:  containers:  - name: xxx    image: xxx    env:    - name: MYSQL_HOST      valueFrom:        configMapKeyRef:          name: xxx          key: MYSQL_HOST    - name: MYSQL_PORT      valueFrom:        configMapKeyRef:          name: xxx          key: MYSQL_PORT    - name: MYSQL_DATABASE      value: "xxx"

3.8.2 引用secret

spec:  containers:  - name: xxx    image: xxx    env:    - name: MYSQL_USER      valueFrom:        secretKeyRef:          name: xxx          key: MYSQL_USER    - name: MYSQL_ROOT_PASSWORD      valueFrom:        secretKeyRef:          name: xxx          key: MYSQL_PASSWD    - name: MYSQL_DATABASE      value: "xxx"

3.9 pod 生命周期

Pod状态值描述

  • Pending: API Server已经创建该Pod,等待调度器调度。
  • ContainerCreating: 拉取镜像启动容器中
  • Runnung: Pod内所有容器均已创建,且至少有一个容器处于运行状态、正在启动状态或正在重启状态。
  • Succeeded| Completed: Pod内所有容器均成功执行后退出,且不会再重启。
  • Failed | Error: Pod内所有容器均已退出,但至少有一个容器退出为失败状态。
  • CrashLoopBackOff: Pod内有容器启动失败,比如配置文件丢失导致主进程启动失败
  • Unknown: 由于某种原因无法获取该Pod的状态,可能由于网络通信不畅导致。

初始化容器(init)

  • 验证业务应用依赖的组件是否均已启动
  • 修改目录的权限
  • 调整系统参数

验证Pod生命周期

apiVersion: v1
kind: Pod
metadata:
name: nginx
namespace: default
labels:
component: nginx
spec:
# 在业务pod启动前启动, 可用于处理一些业务pod启动前的一些工作
initContainers:
- name: nginx1
image: nginx
# 容器启动后写入文件时间和标记
command: ['sh', '-c', 'echo $(date +%s): INIT >> /loap/timing']
volumeMounts:
- mountPath: /loap
name: timing
containers:
- name: nginx2
image: nginx
command: ['sh', '-c', 'echo $(date +%s): START >> /loap/timing; sleep 10; echo $(date +%s): END >> /loap/timing;']
volumeMounts:
- mountPath: /loap
name: timing
livenessProbe: # 存活性探测探针
exec:
command: ['sh', '-c', 'echo $(date +%s): LIVENESS >> /loap/timing']
readinessProbe: # 可用性探测探针
exec:
command: ['sh', '-c', 'echo $(date +%s): READINESS >> /loap/timing']
lifecycle: # 生命周期
postStart: # 容器启动的时候触发
exec:
command: ['sh', '-c', 'echo $(date +%s): POST-START >> /loap/timing']
# 须主动杀掉 Pod 才会触发 pre-stop hook,如果是 Pod 自己 Down 掉,则不会执行 pre-stop hook
preStop:
exec:
command: ['sh', '-c', 'echo $(date +%s): PRE-STOP >> /loap/timing']
volumes:
- name: timing
hostPath:
path: /tmp/loap
kubectl apply -f nginx.yaml# 查看pod所在机器kubectl get pod -o wide# 在pod所在机器查看文件cat /tmp/loap/timing
1630456396: INIT1630456398: START1630456398: POST-START1630456398: READINESS1630456406: LIVENESS1630456406: READINESS1630456408: END
# 删除测试pod, 否则由于没有常驻进程, pod会一直重启kubectl delete -f nginx.yaml

4. 控制器

控制器又称工作负载是用于实现管理pod的中间层,确保pod资源符合预期的状态,pod的资源出现故障时,会尝试 进行重启,当根据重启策略无效,则会重新新建pod的资源。

  • ReplicaSet: 代用户创建指定数量的pod副本数量,确保pod副本数量符合预期状态,并且支持滚动式自动扩容和缩容功能
  • Deployment:工作在ReplicaSet之上,用于管理无状态应用,目前来说最好的控制器。支持滚动更新和回滚功能,提供声明式配置
  • DaemonSet:用于确保集群中的每一个节点只运行特定的pod副本,通常用于实现系统级后台任务。比如EFK服务
  • Job:只要完成就立即退出,不需要重启或重建
  • Cronjob:周期性任务控制,不需要持续后台运行
  • StatefulSet:管理有状态应用

4.1 Deployment

Deployment支持的写法: deployment, deploy

apiVersion: apps/v1kind: Deploymentmetadata:  name: nginx  namespace: defaultspec:  replicas: 1  # 指定Pod副本数  selector:  # 指定Pod的选择器    matchLabels:      app: nginx  template: # temlate中内容与创建pod基本一致    metadata:      labels:  # 给Pod打label        app: nginx    spec:      containers:      - image: nginx        name: nginx        resources: {}      dnsPolicy: ClusterFirst      restartPolicy: Always
# 创建Deploymentkubectl create -f nginx.yaml kubectl create deploy --image=nginx nginx# 通过试运行获取基础yamlkubectl create deploy --image=nginx nginx --dry-run -o yaml# 查看Deployment, -n 可加命名空间kubectl get deploy# 会自动创建replicaSet, 可以查看kubectl get replicaset(rs) # 使用创建文件删除Deploymentkubectl delete -f nginx.yaml # 更新--修改配置文件后执行applykubectl apply -f nginx.yaml# 在线更新, 类似于vim编辑器, 保存后自动更新kubectl edit deploy nginx# 直接使用命令更新kubectl set image deploy nginx nginx=nginx:1.21.1 --record

4.2 副本数

controller(控制器)实时检测pod状态,并保障副本数一直处于期望的值

spec:  replicas: 1  # 指定Pod副本数
# 修改副本数kubectl scale deploy nginx --replicas=2# 最好是通过修改配置文件中replicas参数重新apply来修改副本数(保持配置文件与实际运行状况一致)# 我们删除一个pod, 控制器会重新创建一个kubectl delete pod nginx-6799fc88d8-7rppv
[root@k8s-n-1 ~]# kubectl get podNAME                     READY   STATUS    RESTARTS   AGEnginx-6799fc88d8-7rppv   1/1     Running   0          9m5snginx-6799fc88d8-fnwqr   1/1     Running   0          56s[root@k8s-n-1 ~]# kubectl delete pod nginx-6799fc88d8-7rppvpod "nginx-6799fc88d8-7rppv" deleted[root@k8s-n-1 ~]# kubectl get podNAME                     READY   STATUS              RESTARTS   AGEnginx-6799fc88d8-fnwqr   1/1     Running             0          97snginx-6799fc88d8-grxfs   0/1     ContainerCreating   0          2s

4.3 Pod驱逐策略

K8S 有个特色功能叫 pod eviction,它在某些场景下如节点 NotReady,或者资源不足时,把 pod 驱逐至其它节点,这也是出于业务保护的角度去考虑的

4.4 更新策略

spec:  replicas: 2  # 指定Pod副本数  selector:  # 指定Pod的选择器    matchLabels:      app: myblog  strategy:    rollingUpdate:      maxSurge: 25%      maxUnavailable: 25%    type: RollingUpdate # 指定更新方式为滚动更新,默认策略,通过kubectl get deploy -o yaml查看

策略控制:

  • maxSurge:最大激增数, 指更新过程中, 最多可以比replicas预先设定值多出的pod数量, 可以为固定值或百分比,默认为desired Pods数的25%。计算时向上取整(比如3.4,取4),更新过程中最多会有replicas + maxSurge个pod
  • maxUnavailable: 指更新过程中, 最多有几个pod处于无法服务状态 , 可以为固定值或百分比,默认为desired Pods数的25%。计算时向下取整(比如3.6,取3)
# 我们修改一下nginx镜像版本kubectl set image deploy nginx nginx=nginx:1.21.1 --record# 查看滚动更新事件kubectl describe deploy nginx
Events:  Type    Reason             Age                  From                   Message  ----    ------             ----                 ----                   -------  Normal  ScalingReplicaSet  35s                  deployment-controller  Scaled up replica set nginx-54f48578cf to 1  Normal  ScalingReplicaSet  32s (x2 over 5m5s)   deployment-controller  Scaled down replica set nginx-6799fc88d8 to 2  Normal  ScalingReplicaSet  32s                  deployment-controller  Scaled up replica set nginx-54f48578cf to 2  Normal  ScalingReplicaSet  29s                  deployment-controller  Scaled down replica set nginx-6799fc88d8 to 1  Normal  ScalingReplicaSet  29s                  deployment-controller  Scaled up replica set nginx-54f48578cf to 3  Normal  ScalingReplicaSet  27s                  deployment-controller  Scaled down replica set nginx-6799fc88d8 to 0
  • 我们有三个节点, 所以最多可以增加1个pod, 最多可以有0个pod处于无法服务状态(即至少要保持三个pod在运行中)
  • 3 old pod, 增加的策略触发成功增加一个pod, 减少的策略触发失败
  • 3 old pod + 1 new pod, 增加的策略触发失败, 减少的策略触发成功, 减少一个旧pod
  • 2 old pod + 1 new pod, 增加1减少0
  • 2 old pod + 2 new pod, 增加0减少1
  • 1 old pod + 2 new pod, 增加1减少0
  • 1 old pod + 3 new pod, 新的pod数满足需求, 旧的pod减少1
  • 3 new pod 完成更新

4.5 服务回滚

通过滚动升级的策略可以平滑的升级Deployment,若升级出现问题,需要最快且最好的方式回退到上一次能够提供正常工作的版本。为此K8S提供了回滚机制

revision:更新应用时,K8S都会记录当前的版本号,即为revision,当升级出现问题时,可通过回滚到某个特定的revision,默认配置下,K8S只会保留最近的几个revision,可以通过Deployment配置文件中的spec.revisionHistoryLimit属性增加revision数量,默认是10。

# 查看当前版本及版本历史, 如果是<none>是因为创建和更新的时候没有加--record kubectl rollout history deploy nginx# 我们删除服务重建一下kubectl delete -f nginx.yamlkubectl apply -f nginx.yaml --record# 然后修改一下kubectl set image deploy nginx nginx=nginx:1.21.1 --record# 重新查看历史版本kubectl rollout history deploy nginx
[root@k8s-n-1 ~]# kubectl rollout history deploy nginxdeployment.apps/nginx REVISION  CHANGE-CAUSE1         kubectl apply --filename=nginx.yaml --record=true2         kubectl set image deploy nginx nginx=nginx:1.21.1 --record=true
# 回滚到具体的版本kubectl rollout undo deploy nginx --to-revision=1
[root@k8s-n-1 ~]# kubectl rollout undo deploy nginx --to-revision=1deployment.apps/nginx rolled back[root@k8s-n-1 ~]# kubectl rollout history deploy nginxdeployment.apps/nginx REVISION  CHANGE-CAUSE2         kubectl set image deploy nginx nginx=nginx:1.21.1 --record=true3         kubectl apply --filename=nginx.yaml --record=true

我们看到本该再增加一条记录的历史记录却只有两条记录, 是因为1和3是同一个版本, 则只保留一条

5. Service

service别名: services, service, svc

通过上面,能够通过Deployment来创建一组Pod来提供具有高可用性的服务。虽然每个Pod都会分配一个单独的Pod IP,然而却存在如下两个问题:

  • Pod IP仅仅是集群内可见的虚拟IP,外部无法访问
  • Pod IP会随着Pod的销毁而消失,当ReplicaSet对Pod进行动态伸缩时,Pod IP可能随时随地都会变化,这样对于访问这个服务带来了难度

5.1 Service负载均衡之Cluster IP

service是一组pod的服务抽象,相当于一组pod的LB,负责将请求分发给对应的pod。service会为这个LB提供一个IP,一般称为cluster IP 。使用Service对象,通过selector进行标签选择,找到对应的Pod

apiVersion: v1kind: Servicemetadata:  name: nginx  namespace: defaultspec:  ports:  - port: 80    protocol: TCP    targetPort: 80  selector:    app: nginx  type: ClusterIP
# 创建
kubectl apply -f svc-nginx.yaml
kubectl expose deployment nginx --port=80 --type=ClusterIP
# 查看svc
kubectl get svc
# 删除
kubectl delete svc nginx
# 查看svc详情
kubectl describe svc nginx
[root@k8s-n-1 ~]# kubectl describe svc nginx
Name: nginx
Namespace: default
Labels: <none>
Annotations: <none>
Selector: app=nginx # 根据此label筛选其可操控的pod
Type: ClusterIP
IP Family Policy: SingleStack
IP Families: IPv4
IP: 10.1.156.133
IPs: 10.1.156.133
Port: <unset> 80/TCP
TargetPort: 80/TCP
Endpoints: 10.2.1.12:80,10.2.2.7:80
Session Affinity: None
Events: <none>

我们现在就可以在集群内部用 10.1.156.133 来访问服务了

5.1.1 Endpoint

service对象创建的同时,会创建同名的endpoints对象,若服务设置了readinessProbe, 当readinessProbe检测失败时,endpoints列表中会剔除掉对应的pod_ip,这样流量就不会分发到健康检测失败的Pod中

# 查看endpoint, 与service中的Endpoints内容一致kubectl get endpoints nginx

5.1.2 存在的问题

目前使用hostNetwork部署, 需通过宿主机ip+port访问, 就会有以下问题

  • 服务使用hostNetwork,使得宿主机的端口大量暴漏,存在安全隐患
  • 容易引发端口冲突

服务均属于k8s集群,尽可能使用k8s的网络访问,因此可以对目前myblog访问mysql的方式做改造:

  • 为mysql创建一个固定clusterIp的Service,把clusterIp配置在myblog的环境变量中
  • 利用集群服务发现的能力,组件之间通过service name来访问

5.2 服务发现

在k8s集群中,组件之间可以通过定义的Service名称实现通信

虽然podip和clusterip都不固定,但是service name是固定的,而且具有完全的跨集群可移植性,因此组件之间调用的同时,完全可以通过service name去通信,这样避免了大量的ip维护成本,使得服务的yaml模板更加简单。

# 再起一个服务, 来验证一下kubectl create deployment tomcat --image=tomcatkubectl expose deployment tomcat --port=8080 --type=ClusterIP# 再tomcat容器中请求nginx服务kubectl exec -it tomcat-7d987c7694-qgfxv -- bash# 可以直接使用svc name访问服务curl nginx# 查看pod解析配置cat /etc/resolv.conf
root@tomcat-7d987c7694-qgfxv:~# cat /etc/resolv.confnameserver 10.1.0.10search default.svc.cluster.local svc.cluster.local cluster.localoptions ndots:5
# 上面的10.1.0.10是dns的ip[root@k8s-n-1 ~]# kubectl get svc -n kube-systemNAME       TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)                  AGEkube-dns   ClusterIP   10.1.0.10    <none>        53/UDP,53/TCP,9153/TCP   10d

启动pod的时候,会把kube-dns服务的cluster-ip地址注入到pod的resolve解析配置中,同时添加对应的namespace的search域。 因此跨namespace通过service name访问的话,需要添加对应的namespace名称

# 根据resolv.conf的配置, 下述地址都可请求nginx服务curl nginxcurl nginx.default  # 可实现跨命名空间通讯curl nginx.default.svccurl nginx.default.svc.cluster.local

5.3 Service负载均衡之NodePort

cluster-ip为虚拟地址,只能在k8s集群内部进行访问,集群外部如果访问内部服务,实现方式之一为使用NodePort方式。NodePort会默认在 30000-32767 ,不指定的会随机使用其中一个

apiVersion: v1kind: Servicemetadata:  name: nginx  namespace: defaultspec:  ports:  - port: 80    protocol: TCP    targetPort: 80  selector:    app: nginx  type: NodePort
# 创建kubectl apply -f svc-nginx.yamlkubectl expose deployment nginx2 --port=80 --type=NodePort
# 启动后就可用机器ip(任意node都可以)+port访问nginx服务了curl 192.169.8.1:31429curl 192.169.8.2:31429curl 192.169.8.3:31429

我们也可以在同一局域网内的浏览器访问到nginx服务

5.4 kube-proxy

运行在每个节点上,监听 API Server 中服务对象的变化,再通过创建流量路由规则来实现网络的转发。官方文档

有三种模式:

  • User space, 让 Kube-Proxy 在用户空间监听一个端口,所有的 Service 都转发到这个端口,然后 Kube-Proxy 在内部应用层对其进行转发 , 所有报文都走一遍用户态,性能不高,k8s v1.2版本后废弃
  • Iptables, 当前默认模式,完全由 IPtables 来实现, 通过各个node节点上的iptables规则来实现service的负载均衡,但是随着service数量的增大,iptables模式由于线性查找匹配、全量更新等特点,其性能会显著下降
  • IPVS, 与iptables同样基于Netfilter,但是采用的hash表,因此当service数量达到一定规模时,hash查表的速度优势就会显现出来,从而提高service的服务性能。 k8s 1.8版本开始引入,1.11版本开始稳定,需要开启宿主机的ipvs模块

iptables模式示意图:

[root@k8s-n-1 ~]# iptables-save | grep "default/nginx"
-A KUBE-NODEPORTS -p tcp -m comment --comment "default/nginx" -m tcp --dport 31429 -j KUBE-SVC-2CMXP7HKUVJN7L6M
-A KUBE-SEP-QEWF37NALXUNKCQB -s 10.2.1.13/32 -m comment --comment "default/nginx" -j KUBE-MARK-MASQ
-A KUBE-SEP-QEWF37NALXUNKCQB -p tcp -m comment --comment "default/nginx" -m tcp -j DNAT --to-destination 10.2.1.13:80
-A KUBE-SEP-THS5ZWJX3A5H6VN4 -s 10.2.1.12/32 -m comment --comment "default/nginx" -j KUBE-MARK-MASQ
-A KUBE-SEP-THS5ZWJX3A5H6VN4 -p tcp -m comment --comment "default/nginx" -m tcp -j DNAT --to-destination 10.2.1.12:80
-A KUBE-SERVICES -d 10.1.162.20/32 -p tcp -m comment --comment "default/nginx cluster IP" -m tcp --dport 80 -j KUBE-SVC-2CMXP7HKUVJN7L6M
-A KUBE-SVC-2CMXP7HKUVJN7L6M ! -s 10.2.0.0/16 -d 10.1.162.20/32 -p tcp -m comment --comment "default/nginx cluster IP" -m tcp --dport 80 -j KUBE-MARK-MASQ
-A KUBE-SVC-2CMXP7HKUVJN7L6M -p tcp -m comment --comment "default/nginx" -m tcp --dport 31429 -j KUBE-MARK-MASQ
-A KUBE-SVC-2CMXP7HKUVJN7L6M -m comment --comment "default/nginx" -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-THS5ZWJX3A5H6VN4
-A KUBE-SVC-2CMXP7HKUVJN7L6M -m comment --comment "default/nginx" -j KUBE-SEP-QEWF37NALXUNKCQB

6. Kubernetes服务访问之Ingress

对于Kubernetes的Service,无论是Cluster-Ip和NodePort均是四层的负载,集群内的服务如何实现七层的负载均衡,这就需要借助于Ingress,Ingress控制器的实现方式有很多,比如nginx, Contour, Haproxy, trafik, Istio。

Ingress-nginx是7层的负载均衡器 ,负责统一管理外部对k8s cluster中Service的请求。主要包含:

  • ingress-nginx-controller:根据用户编写的ingress规则(创建的ingress的yaml文件),动态的去更改nginx服务的配置文件,并且reload重载使其生效(是自动化的,通过lua脚本来实现);
  • Ingress资源对象:将Nginx的配置抽象成一个Ingress对象

实现逻辑

  • ingress controller通过和kubernetes api交互,动态的去感知集群中ingress规则变化

  • 然后读取ingress规则(规则就是写明了哪个域名对应哪个service),按照自定义的规则,生成一段nginx配置

  • 再写到nginx-ingress-controller的pod里,这个Ingress controller的pod里运行着一个Nginx服务,控制器把生成的nginx配置写入/etc/nginx/nginx.conf文件中

  • 然后reload一下使配置生效。以此达到域名分别配置和动态更新的问题

6.1 安装

官方文档

# 一般多试几次就能下载下来
wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.0.0/deploy/static/provider/baremetal/deploy.yaml
sed -i "s#k8s.gcr.io/ingress-nginx/controller:v1.0.0.*#registry.cn-hangzhou.aliyuncs.com/google_containers/nginx-ingress-controller:v1.0.0#" deploy.yaml
sed -i "s#k8s.gcr.io/ingress-nginx/kube-webhook-certgen:v1.0.*#hzde0128/kube-webhook-certgen:v1.0#g" deploy.yaml
kubectl apply -f deploy.yaml
kubectl get pod -n ingress-nginx -owide
kubectl describe pod -n ingress-nginx
# 查看webhook
kubectl get validatingwebhookconfigurations
# 删除ingress-nginx-admission
kubectl delete -A ValidatingWebhookConfiguration ingress-nginx-admission

6.2 使用

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
# 可通过kubectl get ingressclass 查看ingressClassName
ingressClassName: nginx
rules:
- host: nginx.openstudy.space
http:
paths:
- path: /
pathType: Prefix
backend:
service:
# 服务的service name
name: nginx
port:
# 服务开放的端口
number: 80
kubectl apply -f ingress.yaml
# 没有域名可以添加hosts测试, 换成自己的ip
vi /etc/hosts
# 192.169.8.1 nginx.openstudy.space
yum -y install
ifconfig cni0 down
ifconfig flannel.1 down
ifconfig del flannel.1
ifconfig del cni0 ip link del flannel.1
ip link del cni0 yum -y install bridge-utils
brctl delbr flannel.1 kubectl delete -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml ip link del flannel.1
ip link del cni0
rm -rf /var/lib/cni/
rm -f /etc/cni/net.d/*
systemctl restart kubelet kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml

k8s资源管理(基础操作)的更多相关文章

  1. python基础操作以及hdfs操作

    目录 前言 基础操作 hdfs操作 总结 一.前言        作为一个全栈工程师,必须要熟练掌握各种语言...HelloWorld.最近就被"逼着"走向了python开发之路, ...

  2. MYSQL基础操作

    MYSQL基础操作 [TOC] 1.基本定义 1.1.关系型数据库系统 关系型数据库系统是建立在关系模型上的数据库系统 什么是关系模型呢? 1.数据结构可以规定,同类数据结构一致,就是一个二维的表格 ...

  3. 【Learning Python】【第二章】Python基础类型和基础操作

    基础类型: 整型: py 3.0解决了整数溢出的问题,意味着整型不必考虑32位,64位,有无符号等问题,你写一个1亿亿亿,就是1亿亿亿,不会溢出 a = 10 ** 240 print(a) 执行以上 ...

  4. Emacs学习心得之 基础操作

    作者:枫雪庭 出处:http://www.cnblogs.com/FengXueTing-px/ 欢迎转载 Emacs学习心得之 基础操作 1.前言与学习计划2.Emacs基础操作 一. 前言与学习计 ...

  5. Git基础操作

    配置秘钥 1.检查本机有没有秘钥 检查~/.ssh看看是否有名为d_rsa.pub和id_dsa.pub的2个文件. $ ~/.sshbash: /c/Users/lenovo/.ssh: Is a ...

  6. activiti基础操作

    package activitiTest; import java.io.InputStream; import java.util.List; import java.util.zip.ZipInp ...

  7. 《Genesis-3D开源游戏引擎-官方录制系列视频教程:基础操作篇》

    注:本系列教程仅针对引擎编辑器:v1.2.2及以下版本 G3D基础操作   第一课<G3D编辑器初探> G3D编辑器介绍,依托于一个复杂场景,讲解了场景视图及其基本操作,属性面板和工具栏的 ...

  8. MYSQL 基础操作

    1.MySQL基础操作 一:MySQL基础操作 1:MySQL表复制 复制表结构 + 复制表数据 create table t3 like t1; --创建一个和t1一样的表,用like(表结构也一样 ...

  9. php之文件基础操作

    在php中对文件的基础操作非常的简单,php提供的函数粗略的用了一遍. file_get_contents():可以获取文件的内容获取一个网络资源的内容,这是php给我封装的一个比较快捷的读取文件的内 ...

  10. ArcGIS Pro 简明教程(2)基础操作和简单制图

    ArcGIS Pro 简明教程(2)基础操作和简单制图 By 李远祥 本章主要介绍ArcGIS Pro如何加载数据并进行简单的地图制作,以基本的操作为主. 上一章节介绍过,ArcGIS Pro是可以直 ...

随机推荐

  1. 【2016-11-3】【坚持学习】【Day18】【ADO.NET 】

    使用Connection创建数据库连接 使用Command创建命令 使用ExecuteScalar,ExecuteNonQuery,ExecuteReader方法来执行命令 使用DataReader来 ...

  2. LabVIEW之生产者/消费者模式--队列操作 彭会锋

    LabVIEW之生产者/消费者模式--队列操作 彭会锋 本文章主要是对学习LabVIEW之生产者/消费者模式的学习笔记,其中涉及到同步控制技术-队列.事件.状态机.生产者-消费者模式,这几种技术在在本 ...

  3. Newtonsoft.Json(Json.net)的基本用法

    Newtonsoft.Json(Json.net)的基本用法 其它资料 JSON详解 添加引用: 使用NuGet,命令:install-package Newtonsoft.Json 实体类: pub ...

  4. Java JPA 查询实体部分字段

    前言 相信大家在用Java JPA作为ORM的时候都会有这种困惑,就是某个表T我仅仅希望取到其中的A.B.C三个字段,可是jpa是通过Entity Class映射的方式组合查询结果的. 那么如何通过使 ...

  5. 认识Ant

    Ant是一个Apache基金会下的跨平台的构件工具,它可以实现项目的自动构建和部署等功能.在本文中,主要让读者熟悉怎样将Ant应用到Java项目中,让它简化构建和部署操作. 一.            ...

  6. [Tools] Wireshark Primer Tutorials

    介绍就不说了,安装也没必要讲,关于如何使用,网上的辣鸡文过多,视频又太冗余. 我推荐看下面有条理的入门教程. 界面说明:http://openmaniak.com/cn/wireshark_use.p ...

  7. alibaba的FastJson找不到JSON对象问题

    在现在出现使用JSON.toJsonString()方法时,可能没有JSON这个对象. 这种问题可能是下载的jar版本比较高.在低版本的jar使用的是JSON对象. 我使用的是1.2.47版本的jar ...

  8. PAT 1077 Kuchiguse

    1077 Kuchiguse (20 分)   The Japanese language is notorious for its sentence ending particles. Person ...

  9. SpringBoot Web开发(3) WebMvcConfigurerAdapter过期替代方案

    springboot2.0中 WebMvcConfigurerAdapter过期替代方案 最近在学习尚硅谷的<springboot核心技术篇>,项目中用到SpringMVC的自动配置和扩展 ...

  10. 【395】yield 和 yield from

    yield:生成器 yield from:将生成器 yield 的内容相当于逐一在 yield 一般 参考:Python 3: Using "yield from" in Gene ...