Fork me on GitHub

-linux-kubernetes基础使用

一 kubernates 带来的变革

1 对于开发人员

​ 由于公司业务多,开发环境、测试环境、预生产环境和生产环境都是隔离的,而且除了生产环境,为了节省 成本,其他环境可能是没有日志收集的,在没有用 k8s 的时候,查看线下测试的日志,需要开发或者测试人员, 找到对应的机器,在找到对应的容器,然后才能查看日志,在用了 k8s 之后,开发和测试可以直接在 k8s 的 dashboard 到对应的 namespace,即可定位到业务的容器,然后可以直接通过控制台查看到对应的日志,大大降 低了操作时间。

​ 把应用部署到 k8s 之后,代码的发布、回滚,以及蓝绿发布、金丝雀发布等都变得特别简单,不仅加快了业 务代码迭代的速度,而且全程无需人工干预。目前我们使用 jenkins、gitrunner 进行发版或者回滚等,从开发环 境到测试环境,到生产环境,完全遵守一次构建,多集群、多环境部署,通过不同的启动参数、不同的环境变量、 不同的配置文件实现区分不同的环境。目前已经实现 Python、Java、PHP、NodeJS、Go、.NET Core、Python 等多种语言的一键式发版、一键式回滚,大大提高了开发人员的开发效率。在使用服务网格后,开发人员在开发应用的过程中,不用再关心代码的网络部分,这些功能都被服务网格实 现,让开发人员可以只关心代码逻辑部分,即可实现网络部分的功能,比如:断流、分流、路由、负载均衡、限速和触发故障等功能。测试过程中,可能同时多套环境,当然也会需要再创建一套测试环境,之前测试环境的创建,需要找运维或者自行手工搭建。在迁移至 k8s 集群后,只需要在 jenkins 上点点鼠标即可在 k8s 集群上创建一套新的测试环境。

2 对于运维人员

​ 如果你是一名运维人员,可能经常因为一些重复、繁琐的工作感觉厌倦。比如:这个需要一套新的测试环境,那个需要一套新的测试环境,之前可能需要装系统、装依赖环境、开通权限等等。而如今,可以直接用镜像直接部署一套新的测试环境,甚至全程无需自己干预,开发人员通过 jenkins 或者自动化运维平台即可一键式创建, 大大降低了运维成本。

​ 一开始,公司业务故障,可能是因为基础环境不一致、依赖不一致、端口冲突等等问题,现在实现 Docker镜像部署,k8s 编排,所有的依赖、基础都是一样的,并且环境的自动化扩容、健康检查、容灾、恢复都是全自动的,大大减少了因为这类基础问题引发的故障。也有可能公司业务是由于服务器宕机、网络等问题,造成服务 不可用,此类情况均需要运维人员及时去修复,而如今,可能在你收到告警信息的时候,k8s 已经帮你恢复了。 在没有使用 k8s 时,业务应用的扩容和缩容,都需要人工去处理,从采购服务器、上架、到部署依赖环境,不仅需要大量的人力物力,而且非常容易在中间过程出现问题,又要花费大量的时间去查找问题。成功上架后,还需要在前端反代端添加或该服务器,而如今,可以利用 k8s 的弹性计算,一键式进行扩容和缩容,不仅大大提高了运维效率,而且还节省了不少的服务器资源,提高了资源利用率。

​ 对于反代配置方面,比如可能你并不会,或者对 nginx 的配置规则并不熟悉,一些高级的功能你也不会实现,而如今,利用 k8s 的 ingress 即可简单的实现那些复杂的逻辑。并且也不会在遇到 nginx 少加一个斜杠和多加一个斜杠的问题。

​ 对于负载均衡方面,之前负载均衡可能是 Nginx、LVS、HAProxy、F5 等,云上可能是云服务商提供的不在均衡机制。每次添加删除节点时,都需要手动去配置前端负载均衡,手动去匹配后端节点,而如今,使用 k8s 内部的 service 可以动态发现实现自动管理节点,并且支持自动扩容缩容。之前遇到高峰流量时,经常服务器性能不够,需要临时加服务器面对高峰流量,而如今对于高性能 k8s 集群加上 serverless,基本实现无需管理,自动扩容。

​ 对于高可用方面,k8s 天生的高可用功能,彻底释放了双手,无需再去创建各类高可用工具、检测检查脚本。 k8s 支持进程接口级别的健康检查,如发现接口超时或者返回值不正确,会自动处理该问题。

​ 对于中间件搭建方面,根据定义好的资源文件,可以实现秒级搭建各类中间件高可用集群,并且支持一键式扩缩容,如 Redis、RabbitMQ、Zookeeper 等,并且大大减少了出错的概率。

​ 对于应用端口方面,传统行业中,一个服务器可能跑了很多进程,每个进程都有一个端口,需要人为的去配置端口,并且还需要考虑端口冲突的问题,如果有防火墙的话,还需要配置防火墙,在 k8s 中,端口统一管理, 统一配置,每个应用的端口都可设置成一样的,之后通过 service 进行负载均衡,大大降低了端口管理的复杂度和端口冲突。

​ 无论是对于开发人员、测试人员还是运维人员,k8s 的诞生,不仅减少了工作的复杂性,还减少了各种成本。 上述带来的变革只是其中比较小的一部分,更多优点只有用了才能体会到。

3 kubernetes 带来的挑战

​ 首先是对于 k8s 的学习本身就是很难的,概念太多,无从入手,可能学习了一个月也无法入门,甚至连集群 也搭建不出来,使人望而却步。并且 k8s 对运维的技术能力要求比较高,已经不仅仅局限于传统运维,有时候你 可能要修改业务代码等。并且需要掌握的知识也需要很多,你可能需要掌握公司所有使用到的代码,比如代码是 如何进行编译的、如何正确发布、如何修改代码配置文件等,这对于运维人员,也是一种挑战。Kubernetes 之所 以被叫做 k8s,业界有两种说法,通俗的说法是 k 和 s 之间有 8 个字母,另一种比较说法是 k8s 集群至少需要搭 建 8 遍才能搭建成功。当然,在实际使用时,可能不止 8 遍。k8s 的诞生,把运维从传统转变到了 DevOps 方向,需要面临的问题会更多,需要面临的新技术也有很多,但是当你掌握到了 k8s 的核心使用,就会受益终身。

二 dashbord部署

-1.在master节点执行   https://github.com/kubernetes/dashboard/blob/master/aio/deploy/recommended.yaml

# 将该yaml文件写入节点

[root@master01 ~]# vi deployment.yaml   

# 需要更改相关image 的版本
image: registry.cn-hangzhou.aliyuncs.com/k8sos/dashboard:v2.0.5
imagePullPolicy: Always

image: registry.cn-hangzhou.aliyuncs.com/k8sos/metrics-scraper:v1.0.6


[root@master01 ~]# kubectl apply -f  recommended.yaml 


-2.查看端口

[root@master01 ~]# kubectl get pods -n kubernetes-dashboard
NAME                                         READY   STATUS    RESTARTS   AGE
dashboard-metrics-scraper-68b94dcfd8-bzch5   1/1     Running   0          73m
kubernetes-dashboard-5f6ffd8777-7x4qk        1/1     Running   0          73m
[root@master01 ~]# kubectl get svc -n kubernetes-dashboard
NAME                        TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)    AGE
dashboard-metrics-scraper   ClusterIP   10.96.130.201    <none>        8000/TCP   7h50m
kubernetes-dashboard        ClusterIP   10.106.244.253   <none>        443/TCP    7h50m

# 此时得到了kubernetes-dashboard的端口,但是由于k8s对其集群的安全性要求极高,无法从外部访问,所以要修改它的相关配置。
[root@master01 ~]# kubectl edit svc kubernetes-dashboard -n kubernetes-dashboard 
  type: NodePort   # 改成NodePort
  
  
-3.访问
输入:http://192.168.10.10:32230/
Client sent an HTTP request to an HTTPS server.

输入:https://192.168.10.10:32230/
点击高级在点击继续访问

-4.需要获取token令牌登录
[root@master01 ~]# vi token.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: admin-user
  namespace: kube-system

---

apiVersion: rbac.authorization.k8s.io/v1

kind: ClusterRoleBinding

metadata:
  name: admin-user
  annotations:
    rbac.authorization.kubernetes.io/autoupdate: "true"

roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: cluster-admin

subjects:
- kind: ServiceAccount
  name: admin-user
  namespace: kube-system

# 部署该资源清单
[root@master01 ~]# kubectl apply -f token.yaml 
serviceaccount/admin-user created
clusterrolebinding.rbac.authorization.k8s.io/admin-user created

# 获取登录token
[root@master01 ~]# kubectl -n kube-system describe secret $(kubectl -n kube-system get secret | grep admin-user | awk '{print $1}') 
Name:         admin-user-token-wcffx
Namespace:    kube-system
Labels:       <none>
Annotations:  kubernetes.io/service-account.name: admin-user
              kubernetes.io/service-account.uid: 4ab2a685-954d-448b-8327-0ad8ddd69d79

Type:  kubernetes.io/service-account-token

Data
====
ca.crt:     1066 bytes
namespace:  11 bytes
token:      eyJhbGciOiJSUzI1NiIsImtpZCI6IjdFcDBodjVYSUJoZTdJYUxxWEZhNDZNdjVwdl9mQWlxdmdGQVNrVlFadHMifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJrdWJlLXN5c3RlbSIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VjcmV0Lm5hbWUiOiJhZG1pbi11c2VyLXRva2VuLXdjZmZ4Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQubmFtZSI6ImFkbWluLXVzZXIiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC51aWQiOiI0YWIyYTY4NS05NTRkLTQ0OGItODMyNy0wYWQ4ZGRkNjlkNzkiLCJzdWIiOiJzeXN0ZW06c2VydmljZWFjY291bnQ6a3ViZS1zeXN0ZW06YWRtaW4tdXNlciJ9.JhD_sSAzSbyzc90o6U2abfCDMfGMSd7XLCfgLLQn7V33d50glLnk4PqMPghZW1rOfLRMfhNgbNSZFjkFEUtS8CyqBIJ4GwJ3MkKhQpU9MR_nFtcIvUaOvx1YwiyBMqviInzZmbQd8wng5bPl8XWj8wcWlEk_VNpxOGxmi-7XhkCBRMaO2x0ObFtMWzjn1UhtaF5S4gmhB8meui01kBIPnIJJ5G6Bx11ymYGvMlJW0KK4w6G0p07vue-oopZin5CdVf-8btKQTfITyBMVo-w3GuCGRqRiToUM8BwmD3gh3j0x3CELyJfZ0jBopEBkpfrFgtUyql3LuZljR9guxnmN0w

三 pod

​ K8s 有很多技术概念,同时对应很多 API 对象,最重要的也是最基础的是微服务 Pod。Pod 是在 K8s 集群中运 行部署应用或服务的最小单元,它是可以支持多容器的。Pod 的设计理念是支持多个容器在一个 Pod 中共享网络 地址和文件系统,可以通过进程间通信和文件共享这种简单高效的方式组合完成服务。Pod 对多容器的支持是 K8s 最基础的设计理念。比如你运行一个操作系统发行版的软件仓库,一个 Nginx 容器用来发布软件,另一个容器专门用来从源仓库做同步,这两个容器的镜像不太可能是一个团队开发的,但是他们一块儿工作才能提供一个微服务;这种情况下,不同的团队各自开发构建自己的容器镜像,在部署的时候组合成一个微服务对外提供服务。这 就是 K8S 中的 POD。

​ Pod 是 K8s 集群中所有业务类型的基础,可以看作运行在 K8s 集群中的小机器人,不同类型的业务就需要不 同类型的小机器人去执行。目前 K8s 中的业务主要可以分为长期伺服型(long-running)、批处理型(batch)、 节点后台支撑型(node-daemon)和有状态应用型(stateful application);分别对应的小机器人控制器为 Deployment、Job、DaemonSet 和 StatefulSet。

1 Pod的初体验

-1.写一个资源清单
[root@master01 ~]# vi test.yaml 
# k8s当中一切皆资源
# 定义创建的资源
kind: Pod
# 指定API版本号
apiVersion: v1
# 定义当前资源的基础信息
metadata:
  # 定义名称(由字母和数字及中划线组成,必须小写同时必须以字母开头)
  name: test-pod
# 配置资源详情
spec:
  # 配置Pod当中包含的容器
  containers:
    - name: nginx
      image: nginx:1.19.2
      
-2.执行
[root@master01 ~]# kubectl apply -f test.yaml 
pod/test-pod created
[root@master01 ~]# kubectl get -f test.yaml 
NAME       READY   STATUS    RESTARTS   AGE
test-pod   0/1     Pending   0          80s

# 还需要等待整个资源执行完毕 1/1

2 Pod带来的好处

  • Pod作为一个可以独立运行的服务单元,简化了应用部署的难度,以更高的抽象层次为应用部署提供了极大的方便。
  • Pod作为最小的使用实例可以独立运行,因此可以方便的进行部署、水平扩展和收缩、方便调度管理与资源的分配。
  • Pod中的容器共享相同的数据和网络地址空间,Pod之间也进行了同意的资源管理与分配。

3 Pod是如何管理多个容器的

​ Pod中可以同时运行多个进行(作为容器运行)协同工作。。同一个 Pod 中的容器会自动的分配到同一个 node 上。同一个 Pod 中的容器共享资源、网络环境和依赖,所以它们总是被同时调度。在一个 Pod 中同时运行多个容 器是一种比较高级的用法。只有当你的容器需要紧密配合协作的时候才考虑用这种模式。

4 Pod中的数据持久性

​ Pod 在设计⽀持就不是作为持久化实体的。在调度失败、节点故障、缺少资源或者节点维护的状态下都会死 掉会被驱逐。通常,我们是需要借助类似于 Docker 存储卷这样的资源来做 Pod 的数据持久化的。

5 Pod的生命周期和重启策略

​ Pod 在整个生命周期过程中被系统定义为各种状态,熟悉 Pod 各种状态对于我 理解如何设置 Pod 的调度策 略、重启策略是很有必要的。

5.1 Pod的状态

状态栏 描述
挂起(Pending) API Server 创建了 pod 资源对象已存入 etcd 中,但它尚未被调度完成,或者仍处于从仓 库下载镜像的过程中。
运行中(Running) Pod 已经被调度至某节点,并且所有容器都已经被 kubelet 创建完成。
成功(Succeeded) Pod 中的所有容器都已经成功终止并且不会被重启。
失败(Failed) Pod 中的所有容器都已终止了,并且至少有一个容器是因为失败终止。即容器以非 0 状态退出或者被系统禁止。
未知(Uknown) Api Server 无法正常获取到 Pod 对象的状态信息,通常是由于无法与所在工作节点的

5.2 Pod重启策略

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

  • Always:当容器失效时,由 kubelet 自动重启该容器。

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

  • Never:不论容器运行状态如何,kubelet 都不会重启该容器。

​ kubelet 重启失效容器的时间间隔以 sync-frequency 乘以 2n 来计算;例如 1、2、4、8 倍等,最长延时 5min ,并且在成功重启后的 10 min 后重置该时间。

​ Pod 的重启策略与控制方式息息相关,当前可用于管理 Pod 的控制器包括 ReplicationController、Job、DaemonSet 及直接通过 kubelet 管理(静态 Pod)。每种控制器对 Pod 的重启策略要求如下:

  • RC 和 DaemonSet:必须设置为 Always,需要保证该容器持续运行。
  • Job 和 CronJob:OnFailure 或 Never,确保容器执行完成后不再重启。
  • kubelet:在 Pod 失效时自动重启它,不论将 RestartPolicy 设置为什么值,也不会对 Pod 进行健康检查。

6 Pod的资源清单详解

apiVersion: v1 # 必选,API 的版本号 
kind: Pod # 必选,类型 Pod 
metadata: # 必选,元数据 
  name: nginx # 必选,符合 RFC 1035 规范的 Pod 名称 
  namespace: web-testing # 可选,不指定默认为 default,Pod 所在的命名空间 
  labels: # 可选,标签选择器,一般用于 Selector 
    - app: nginx 
  annotations: # 可选,注释列表 
    - app: nginx 
spec: # 必选,用于定义容器的详细信息 
  containers: # 必选,容器列表 
  - name: nginx # 必选,符合 RFC 1035 规范的容器名称 
    image: nginx:v1 # 必选,容器所用的镜像的地址 
    imagePullPolicy: Always # 可选,镜像拉取策略 
    workingDir: /usr/share/nginx/html # 可选,容器的工作目录 
    volumeMounts: # 可选,存储卷配置 
    - name: webroot # 存储卷名称 
      mountPath: /usr/share/nginx/html # 挂载目录 
      readOnly: true # 只读
    ports: # 可选,容器需要暴露的端口号列表 
    - name: http # 端口名称 
      containerPort: 80 # 端口号 
      protocol: TCP # 端口协议,默认 TCP 
    env: # 可选,环境变量配置 
    - name: TZ # 变量名 
      value: Asia/Shanghai 
    - name: LANG 
      value: en_US.utf8 
    resources: # 可选,资源限制和资源请求限制 
      limits: # 最大限制设置 
        cpu: 1000m 
        memory: 1024MiB 
      requests: # 启动所需的资源 
        cpu: 100m 
        memory: 512MiB 
    readinessProbe: # 可选,容器状态检查 
      httpGet: # 检测方式 
        path: / # 检查路径 
        port: 80 # 监控端口 
      timeoutSeconds: 2 # 超时时间 
      initialDelaySeconds: 60 # 初始化时间 
    livenessProbe: # 可选,监控状态检查 
      exec: # 检测方式 
        command: 
        - cat 
        - /health 
      httpGet: # 检测方式 
        path: /_health 
        port: 8080 
        httpHeaders: 
        - name: end-user 
          value: jason 
      tcpSocket: # 检测方式 
        port: 80 
      initialDelaySeconds: 60 # 初始化时间 
      timeoutSeconds: 2 # 超时时间 
      periodSeconds: 5 # 检测间隔 
      successThreshold: 2 # 检查成功为 2 次表示就绪 
      failureThreshold: 1 # 检测失败 1 次表示未就绪 
    securityContext: # 可选,限制容器不可信的行为 
      provoleged: false 
  restartPolicy: Always # 可选,默认为 Always
  nodeSelector: # 可选,指定 Node 节点 
    region: subnet7 
  imagePullSecrets: # 可选,拉取镜像使用的 secret 
  - name: default-dockercfg-86258 
  hostNetwork: false # 可选,是否为主机模式,如是,会占用主机端口 
  volumes: # 共享存储卷列表 
  - name: webroot # 名称,与上述对应 
    emptyDir: {} # 共享卷类型,空 
    hostPath: # 共享卷类型,本机目录 
      path: /etc/hosts 
    secret: # 共享卷类型,secret 模式,一般用于密码 
      secretName: default-token-tf2jp # 名称 
      defaultMode: 420 # 权限 
      configMap: # 一般用于配置文件 
      name: nginx-conf 
      defaultMode: 420

四 Label

​ Label 是 Kubernetes 系统中另外一个核心概念。一个 Label 是一个 key=value 的键值对,其中 key 与 vaue 由用户自己指定。Label 可以附加到各种资源对象上,例如 Node、Pod、Service、RC 等,一个资源对象可以定义任意数量的 Label,同一个 Label 也可以被添加到任意数量的资源对象上去,Label 通常在资源对象定义时确定,也可以在对象创建后动态添加或者删除。

​ 我们可以通过指定的资源对象捆绑一个或多个不同的 Label 来实现多维度的资源分组管理功能,以便于灵活、方便地进行资源分配、调度、配置、部署等管理工作。例如:部署不同版本的应用到不同的环境中;或者监控和分析应用(日志记录、监控、告警)等。一些常用等 label 示例如下。

  • 版本标签:"release" : "stable" , "release" : "canary"

  • 环境标签:"environment" : "dev" , "environment" : "production"

  • 架构标签:"tier" : "frontend" , "tier" : "backend" , "tier" : "middleware"

  • 分区标签:"partition" : "customerA" , "partition" : "customerB"

  • 质量管控标签:"track" : "daily" , "track" : "weekly"

​ Label 相当于我们熟悉的“标签”,給某个资源对象定义一个 Label,就相当于給它打了一个标签,随后可以通过 Label Selector(标签选择器)查询和筛选拥有某些 Label 的资源对象,Kubernetes 通过这种方式实现了类似SQL 的简单又通用的对象查询机制。

[root@master01 network-scripts]# kubectl get pods --show-labels
NAME                               READY   STATUS        RESTARTS   AGE     LABELS
test-deployment-674d9c85d4-6rwvb   1/1     Running       0          13h     app=test-deployment,env=test,pod-template-hash=674d9c85d4

1 根据标签来查询pod

[root@master01 network-scripts]# kubectl get pods -l pod-template-hash=674d9c85d4
NAME                               READY   STATUS        RESTARTS   AGE
test-deployment-674d9c85d4-6rwvb   1/1     Running       0          13h

五 service 资源

​ service 是 k8s 中的一个重要概念,主要是提供负载均衡和服务自动发现。它是 k8s 中最核心的资源之一,每 一个 Service 就是我们平常所说的一个“微服务”。在非 k8s 世界中,管理员可以通过在配置文件中指定 IP 地址 或主机名,容许客户端访问,但在 k8s 中这种方式是行不通的。因为 Pod 是有生命周期的,它们可以被创建或销毁。虽然通过控制器能够动态地创建 Pod,但当 Pod 被分配到某个节点时,K8s 都会为其分配一个 IP 地址,而 该 IP 地址不总是稳定可依赖的。因此,在 Kubernetes 集群中,如果一组 Pod(称为 backend)为其它 Pod (称 为 frontend)提供服务,那么那些 frontend 该如何发现,并连接到这组 backend 的 Pod 呢?

[root@master01 ~]# kubectl get svc
NAME           TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE
kubernetes     ClusterIP   10.96.0.1       <none>        443/TCP   2d23h
test-service   ClusterIP   10.96.228.253   <none>        80/TCP    85s

[root@master01 ~]# curl 10.244.1.9
# 在集群中可以访问

# 在外不能访问,浏览器上输入不能访问

# 需要制定向外暴露的端口

1 定义 Service

kind: Service 
apiVersion: v1 
metadata: 
  name: test-service 
  namespace: default 
  labels: 
    app: test-service 
spec: 
  type: ClusterIP  # 此定义则是在集群内部访问
  selector: 
    app: test-service 
  ports: 
    - port: 80 					
      targetPort: 80    # 目标端口号

2 Service 类型

Service 是 Kubernetes 对外访问的窗口,针对不同的场景,kubernetes 为我们设置了四种 Service 的类型。

2.1 ClusterIP

kubernetes 默认就是这种方式,是集群内部访问的方式,外部是无法访问的。其主要用于为集群内 Pod 访问时,提供的固定访问地址,默认是自动分配地址,可使用 ClusterIP 关键字指定固定 IP。

[root@kubernetes-master-01 test]# vi ser.yaml

# 写入上部分yaml文件


[root@master01 ~]# kubectl get svc
NAME           TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE
kubernetes     ClusterIP   10.96.0.1       <none>        443/TCP   2d23h
test-service   ClusterIP   10.96.228.253   <none>        80/TCP    85s

[root@master01 ~]# curl 10.96.228.253

# 可在集群内访问

[root@master01 ~]# kubectl describe service test-service
Name:              test-service
Namespace:         default
Labels:            app=test-service
Annotations:       <none>
Selector:          app=test-service
Type:              ClusterIP
IP:                10.96.228.253
Port:              <unset>  80/TCP
TargetPort:        80/TCP
Endpoints:         <none>
Session Affinity:  None
Events:            <none>

2.2 NodePort

NodePort 是将主机 IP 和端口跟 kubernetes 集群所需要暴露的 IP 和端口进行关联,方便其对外提供服务。内 部可以通过 ClusterIP 进行访问,外部用户可以通过 NodeIP:NodePort 的方式单独访问每个 Node 上的实例。

[root@master01 ~]# vi nodeport.yaml
# 定义资源类型
kind: Deployment
# 定义api版本号
apiVersion: apps/v1
# 定义基础信息
metadata:
  name: test-django
# 定义容器信息
spec:
  # 最少运行数量
  replicas: 1
  # 定义pod模板
  template:
    metadata:
      labels:
        app: test-django
        env: test
    spec:
      containers:
        # 容器名字
        - name: django
          # 容器的镜像源
          image: registry.cn-hangzhou.aliyuncs.com/k8s2me/django:v1
  # 定义选择器
  selector:
    # 精确匹配
    matchLabels:
      app: test-django
---
# Service 是 Kubernetes 对外访问的窗口,针对不同的场景,kubernetes 为我们设置了四种 Service 的类型
kind: Service
apiVersion: v1
metadata:
  name: my-service
  namespace: default
  labels:
    app: nginx
spec:
# NodePort 是将主机 IP 和端口跟 kubernetes 集群所需要暴露的 IP 和端口进行关联,方便其对外提供服务。内
  #部可以通过 ClusterIP 进行访问,外部用户可以通过 NodeIP:NodePort 的方式单独访问每个 Node 上的实例。
  type: NodePort
  selector:
    app: test-django
  ports:
    - port: 80
      # 监听的端口
      targetPort: 80
      # node暴露给外面的端口
      nodePort: 30080

# 上述配置创建一个名称为 "my-service" 的 Service 对象,它会将请求代理到使用 TCP 端口 30080,
# 并且具有标签 "test-django" 的 Pod 上。
# Kubernetes 为该服务分配一个 IP 地址(有时称为 "集群IP"),该 IP 地址由服务代理使用。
      
      


[root@master01 ~]# kubectl get pods -o wide
NAME                               READY   STATUS    RESTARTS   AGE     IP            NODE    NOMINATED NODE   READINESS GATES
test-django-6d96c9ddf4-x74z5       1/1     Running   0          16m     10.244.1.13   node1   <none>           <none>
      
[root@master01 ~]# kubectl apply -f nodeport.yaml 
service/my-svc created
[root@master01 ~]# kubectl get svc
NAME           TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
kubernetes     ClusterIP   10.96.0.1       <none>        443/TCP        3d
my-svc         NodePort    10.109.34.201   <none>        80:30080/TCP   7s

[root@master01 ~]# kubectl describe service my-service
Name:                     my-service
Namespace:                default
Labels:                   app=nginx
Annotations:              <none>
Selector:                 app=test-django
Type:                     NodePort
IP:                       10.107.222.87
Port:                     <unset>  80/TCP
TargetPort:               80/TCP
NodePort:                 <unset>  30080/TCP
Endpoints:                <none>
Session Affinity:         None
External Traffic Policy:  Cluster
Events:                   <none>

# 试验是否能连接
[root@master01 ~]# curl 192.168.10.10:30080
"主机名:test-django-6d96c9ddf4-x74z5, 版本:V1"[root@master01 ~]# 

# 主机名不是pod名,而是被分配到子节点的容器名

# 由此由servier资源向外定义的端口30080映射到了集群内部的端口80,可以在外通过端口30080访问。

六 deployment 资源

​ Deployment 为 Pod 提供声明式更新。在 Deployment 对象中描述所需的状态,然后 Deployment 控制器实 际状态以受控的速率更改为所需的状态。您可以定义部署以创建新的副本集,或删除现有部署并在新部署中采用 其所有资源。一句话:Deployment 主要功能是保证有足够的 Pod 正常对外提供服务。

# 定义资源类型
kind: Deployment

# 定义api版本号
apiVersion: apps/v1

# 定义基础信息
metadata:
  name: test-deployment


# 定义容器信息
spec:
  # 定义pod的模板
  template:
    metadata:
      labels:
        app: test-deployment
        env: test
    spec:
      containers:
        - name: nginx
          image: nginx:1.19.2
  # 定义选择器
  selector:
    # 精确匹配
    matchLabels:
      app: test-deployment
      env: test

1 执行创建命令

[root@master01 ~]# vi demployment.yaml 
[root@master01 ~]# kubectl apply -f demployment.yaml 
deployment.apps/test-deployment created
[root@master01 ~]# kubectl get pods
NAME                           READY   STATUS    RESTARTS   AGE
test-django-6d96c9ddf4-x74z5   1/1     Running   0          10m

2 注意

​ 将 kubectl 标志设置--record 为 true 允许您将当前命令记录在正在创建或更新的资源的注释中。这对于将来 的检查很有用。

[root@master01 ~]# kubectl apply -f deployment.yaml --record deployment.apps/nginx-deployment configured

3 查看部署状态

[root@master01 ~]# kubectl get pods
NAME                           READY   STATUS    RESTARTS   AGE
test-django-6d96c9ddf4-x74z5   1/1     Running   0          10m


# 能看到部署在那个子节点上运行以及集群内的ip地址
[root@master01 ~]# kubectl get pods -o wide
NAME                               READY   STATUS    RESTARTS   AGE     IP            NODE    NOMINATED NODE   READINESS GATES
test-deployment-674d9c85d4-6rwvb   1/1     Running   0          5m41s   10.244.1.14   node1   <none>           <none>

4 查看部署详情

[root@master01 ~]# kubectl describe deployment test-deployment    [资源类型] [资源名字]

kubectl describe deployment test-deployment
Name:                   test-deployment
Namespace:              default
CreationTimestamp:      Wed, 09 Dec 2020 11:57:32 +0800
Labels:                 <none>
Annotations:            deployment.kubernetes.io/revision: 1
Selector:               app=test-deployment,env=test
Replicas:               1 desired | 1 updated | 1 total | 0 available | 1 unavailable
StrategyType:           RollingUpdate
MinReadySeconds:        0
RollingUpdateStrategy:  25% max unavailable, 25% max surge
Pod Template:
  Labels:  app=test-deployment
           env=test
  Containers:
   nginx:
    Image:        nginx:1.19.2
    Port:         <none>
    Host Port:    <none>
    Environment:  <none>
    Mounts:       <none>
  Volumes:        <none>
Conditions:
  Type           Status  Reason
  ----           ------  ------
  Progressing    True    NewReplicaSetAvailable
  Available      False   MinimumReplicasUnavailable
OldReplicaSets:  <none>
NewReplicaSet:   test-deployment-674d9c85d4 (1/1 replicas created)
Events:
  Type    Reason             Age   From                   Message
  ----    ------             ----  ----                   -------
  Normal  ScalingReplicaSet  23m   deployment-controller  Scaled up replica set test-deployment-674d9c85d4 to 1

5 更新

一般对应用程序升级或者版本迭代时,会通过Deployment对Pod进行回滚更新。

5.1 设置

[root@master01 ~]# kubectl set image deployment test-deployment nginx=nginx:1.18.0
deployment.apps/test-deployment image updated

# 查看更新状态
[root@master01 ~]# kubectl get pods
NAME                               READY   STATUS              RESTARTS   AGE
test-deployment-674d9c85d4-6rwvb   1/1     Terminating         0          36m
test-deployment-674d9c85d4-7x4qk   0/1     Error               1          10m
test-deployment-6f4888c79c-b9s6w   0/1     Pending             0          83s
test-django-6d96c9ddf4-9dmg6       0/1     ContainerCreating   0          10m
test-django-6d96c9ddf4-x74z5       1/1     Terminating         0          47m

5.2 更新、修改

第一种:通过命令行指定更新

格式:kubectl set image [资源类型(控制器资源)] [资源名称] [容器名称]=[新镜像]

kubectl set image deployment test-deployment django=redis

第二种:通过YAML文件进行修改

第三种:修改资源

kubectl edit [资源类型] [资源名称]

第四种:通过打补丁的方式

kubectl patch [资源类型] [资源名称] -p [配置项]
kubectl patch deployments.apps test-deployment -p '{"spec": {"replicas": 5}}'

七 pod、service、deployment、label具体联系

7.1 Pod

在Docker Swarm中,调度的最小单位是容器,而在K8S中,调度的最小是Pod,那啥是Pod呢?

Pod是K8S设计的一个全新的概念,在英文中的原意是表达一群鲸鱼或者是一个豌豆荚的意思。换句话说,一个Pod中可以运行一个或者多个容器。

在一个集群中,K8S会为每个Pod都分配一个集群内唯一的IP地址。因为K8S要求底层网络支持集群内的任意节点之间的两个Pod能够直接通信。这些容器共享当前Pod的文件系统和网络。而这些容器之所以能够共享,是因为Pod中有一个叫Pause的根容器,其余的用户业务容器都是共享这个根容器的IP和Volume。所以这些容器之间都可以通过localhost进行通信。

有人可能会问,为什么要引入根容器这个概念?那是因为如果没有根容器的话,当一个Pod中引入了多个容器的时候,我们应该用哪一个容器的状态来判断Pod的状态呢?所以才要引入与业务无关且不容易挂掉的Pause容器作为根容器,用根容器的状态来代表整个容器的状态

如果在Pod中容器出现异常终止了是不会重启,在实际使用场景下基本不会直接使用Pod而是使用Deployment部署自己的应用。

熟悉Spring Cloud或者微服务的都知道,微服务中最忌讳的就是出现单点的情况。

所以针对同一个服务我们一般会部署2个或者更多个实例。在K8S中,则是会部署多个Pod副本,组成一个Pod集群来对外提供服务。而这些的具体实施就需要Deployment

而我们前面提过,K8S会为每一个Pod提供一个唯一的IP地址,客户端就需要通过每个Pod的唯一IP+容器端口来访问到具体的Pod,这样一来,如果客户端把调用地址写死,服务器就没有办法做负载均衡,而且,Pod重启之后IP地址是会变的,难道每次重启都要通知客户端IP变更吗?

为了解决这个问题,就要引出Service的概念了。

7.2 Deployment

Deployment是一个定义及管理多副本应用(即多个副本 Pod)的新一代对象,与Replication Controller相比,它提供了更加完善的功能,使用起来更加简单方便。

如果Pod出现故障,对应的服务也会挂掉,所以Kubernetes提供了一个Deployment的概念 ,目的是让Kubernetes去管理一组Pod的副本,也就是副本集 ,这样就能够保证一定数量的副本一直可用,不会因为某一个Pod挂掉导致整个服务挂掉。

Deployment 还负责在 Pod 定义发生变化时,对每个副本进行滚动更新(Rolling Update)。

这样使用一种 API 对象(Deployment)管理另一种 API 对象(Pod)的方法,在 k8s 中,叫作"控制器"模式(controller pattern)。Deployment 扮演的正是 Pod 的控制器的角色。

7.3 Service

Service是K8S中最核心的资源对象之一,就是用于解决上面提到的问题。我个人认为与Swarm中的Service概念没有太大的区别。

一旦Service被创建,K8S会为其分配一个集群内唯一的IP,叫做ClusterIP,而且在Service的整个生命周期中,ClusterIP不会发生变更,这样一来,就可以用与Docker Swarm类似的操作,建立一个ClusterIP到服务名的DNS域名映射即可。

值得注意的是,ClusterIP是一个虚拟的IP地址,无法被Ping,仅仅只限于在K8S的集群内使用。

而Service对客户端,屏蔽了底层Pod的寻址的过程。并且由kube-proxy进程将对Service的请求转发到具体的Pod上,具体到哪一个,由具体的调度算法决定。这样以来,就实现了负载均衡。

而Service是怎么找到Pod的呢?这就需要继续引入另外一个核心概念Label了。

7.4 Label

Lable本质上是一个键值对,具体的值由用户决定。Lable就是标签,可以打在Pod上,也可以打到Service上。总结来说,Label与被标记的资源是一个一对多的关系。

例如,我们给上面所描述的Pod打上了role=serviceA的标签,那么只需要在Service中的Label Selector中加入刚刚那个标签,这样一来,Service就可以通过Label Selector找到打了同一Label的Pod副本集了。

posted @ 2020-12-18 20:52  artherwan  阅读(532)  评论(0编辑  收藏  举报