K8S组件介绍

        在说明k8s的一些使用方法时,我们需要将注意力更多的集中在如何使用k8s本身上,出现警告版本问题时,我们记录下来,后续自行研究即可,这类告警一般在官方文档和命令行中留有充分的解释,在整个k8s架构中,我们需要理解各个组件的规则并运用出来,这些大部分属于标准化操作,重点还是在于不断深入理解各个组件的原理。即使更新版本,原理不会变的情况下,我们需要投入的精力就会事半功倍。

K8S官网:Kubernetes 文档 | Kubernetes

本文留有目录,请自行查看。

Pod管理:

命令:

关于Pod介绍:

        Pod是可以创建和管理 Kubernetes 计算的最小可部署单元,一个 Pod 代表着集群
中运行的一个进程,每个 pod 都有一个唯一的 ip
        一个pod 类似一个豌豆荚,包含一个或多个容器(通常是 docker ),多个容器间
共享 IPC Network UTC namespace

Kubernetes通过Pod解决容器的网络通信和数据共享的问题。

集群内部任意节点可以访问Pod,但集群外部无法直接访问

集群内会分配VIP给pod,pod内的容器共享这一个VIP

先熟悉命令:

查看搭建好的集群是否ready:

[root@k8s1 ~]# kubectl get nodes
NAME   STATUS   ROLES                  AGE     VERSION
k8s1   Ready    control-plane,master   2d15h   v1.23.12
k8s2   Ready    <none>                 2d14h   v1.23.12
k8s3   Ready    <none>                 2d15h   v1.23.12

查看所有的pod:

这里显示了所有的pod

[root@k8s1 ~]# kubectl get pod -A
NAMESPACE      NAME                           READY   STATUS    RESTARTS       AGE
kube-flannel   kube-flannel-ds-df8rj          1/1     Running   4 (37h ago)    2d15h
kube-flannel   kube-flannel-ds-kbqz4          1/1     Running   2 (37h ago)    2d14h
kube-flannel   kube-flannel-ds-n5j5h          1/1     Running   6 (71m ago)    2d15h
kube-system    coredns-7b56f6bc55-9kjf8       1/1     Running   10 (15h ago)   2d15h
kube-system    coredns-7b56f6bc55-rrrjt       1/1     Running   11 (15h ago)   2d15h
kube-system    etcd-k8s1                      1/1     Running   6 (15h ago)    2d15h
kube-system    kube-apiserver-k8s1            1/1     Running   6 (15h ago)    2d15h
kube-system    kube-controller-manager-k8s1   1/1     Running   6 (15h ago)    2d15h
kube-system    kube-proxy-jcz7l               1/1     Running   2 (37h ago)    2d15h
kube-system    kube-proxy-rxcdx               1/1     Running   2 (37h ago)    2d14h
kube-system    kube-proxy-vthg8               1/1     Running   5 (15h ago)    2d15h
kube-system    kube-scheduler-k8s1            1/1     Running   6 (15h ago)    2d15h

单单查看pod时namespace默认查看的是default:

[root@k8s1 ~]# kubectl get pod
No resources found in default namespace.

[root@k8s1 ~]# kubectl get pod -n ns
No resources found in ns namespace.
[root@k8s1 ~]# kubectl get pod -n kube-flannel

可以选择 -n 查看任意的namespace
NAME                    READY   STATUS    RESTARTS        AGE
kube-flannel-ds-df8rj   1/1     Running   4 (41h ago)     2d19h
kube-flannel-ds-kbqz4   1/1     Running   2 (41h ago)     2d18h
kube-flannel-ds-n5j5h   1/1     Running   6 (4h41m ago)   2d19h
[root@k8s1 ~]# kubectl get pod -n kube-system
NAME                           READY   STATUS    RESTARTS       AGE
coredns-7b56f6bc55-9kjf8       1/1     Running   10 (18h ago)   2d19h
coredns-7b56f6bc55-rrrjt       1/1     Running   11 (18h ago)   2d19h
etcd-k8s1                      1/1     Running   6 (18h ago)    2d19h
kube-apiserver-k8s1            1/1     Running   6 (18h ago)    2d19h
kube-controller-manager-k8s1   1/1     Running   6 (18h ago)    2d19h
kube-proxy-jcz7l               1/1     Running   2 (41h ago)    2d19h
kube-proxy-rxcdx               1/1     Running   2 (41h ago)    2d18h
kube-proxy-vthg8               1/1     Running   5 (18h ago)    2d19h
kube-scheduler-k8s1            1/1     Running   6 (18h ago)    2d19h

创建一个pod,指定镜像为nginx

kubectl run demo --image=nginx

[root@k8s1 ~]# kubectl get pod
NAME   READY   STATUS              RESTARTS   AGE
demo   0/1     ContainerCreating   0          10s

“ContainerCreating”    正在创建中

[root@k8s1 ~]# kubectl get pod
NAME   READY   STATUS    RESTARTS   AGE
demo   1/1     Running   0          14s

[root@k8s1 ~]# kubectl get pod -o wide
## -o wide 是用来查看pod的详细信息

NAME   READY   STATUS    RESTARTS   AGE   IP           NODE   NOMINATED NODE   READINESS GATES
demo   1/1     Running   0          34s   10.244.2.2   k8s2   <none>           <none>

##此时pod被创建在k8s2节点上

此时在集群内任意节点可以访问pod:

[root@k8s1 ~]# curl 10.244.1.13
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

删除pod:

kubectl delete pod demo

此时的pod是自主式pod,删除之后即完全删除

现在创建deployment控制器demo:

[root@k8s1 ~]# kubectl create deployment demo --image=nginx
deployment.apps/demo created

##成功创建

[root@k8s1 ~]# kubectl get pod
NAME                    READY   STATUS    RESTARTS   AGE
demo-6c54f77c95-8rhtd   1/1     Running   0          5s

##查看pod

[root@k8s1 ~]# kubectl get deployments.apps
NAME   READY   UP-TO-DATE   AVAILABLE   AGE
demo   1/1     1            1           28s

##查看控制器demo

[root@k8s1 ~]# kubectl delete pod demo-6c54f77c95-8rhtd
pod "demo-6c54f77c95-8rhtd" deleted

##在删除pod demo之后,由于创建了控制器,pod会自愈

[root@k8s1 ~]# kubectl get pod
NAME                    READY   STATUS              RESTARTS   AGE
demo-6c54f77c95-rblxf   0/1     ContainerCreating   0          6s

##此时pod又在被创建

[root@k8s1 ~]# kubectl scale deployment demo --replicas=3

##指定拉伸副本数为三个

deployment.apps/demo scaled


[root@k8s1 ~]# kubectl get pod
NAME                    READY   STATUS    RESTARTS   AGE
demo-6c54f77c95-4chxb   1/1     Running   0          5s
demo-6c54f77c95-rblxf   1/1     Running   0          48s
demo-6c54f77c95-v7t5q   1/1     Running   0          5s

##此时三个pod被创建好了

[root@k8s1 ~]# kubectl scale deployment demo --replicas=1

##此时副本数又被缩回至1个

deployment.apps/demo scaled

[root@k8s1 ~]# kubectl get pod
NAME                    READY   STATUS    RESTARTS   AGE
demo-6c54f77c95-4chxb   1/1     Running   0          37s

##查看pod

此时pod只能被集群内部访问,如果想让集群外访问需要把控制器暴露出来:

[root@k8s1 ~]# kubectl expose deployment demo --port=80 --target-port=80

##--target-por 容器内端口
service/demo exposed

[root@k8s1 ~]# kubectl get svc
NAME         TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE
demo         ClusterIP   10.104.93.185   <none>        80/TCP    10s
kubernetes   ClusterIP   10.96.0.1       <none>        443/TCP   2d16h

此时会创建一个demo的svc

查看此时的svc,endpoint只有一个IP
[root@k8s1 ~]# kubectl describe svc demo
Name:              demo
Namespace:         default
Labels:            app=demo
Annotations:       <none>
Selector:          app=demo
Type:              ClusterIP
IP Family Policy:  SingleStack
IP Families:       IPv4
IP:                10.109.224.102
IPs:               10.109.224.102
Port:              <unset>  80/TCP
TargetPort:        80/TCP
Endpoints:         10.244.1.14:80
Session Affinity:  None
Events:            <none>



此时将副本数拉伸为3:
[root@k8s1 ~]# kubectl expose deployment demo --port=80 --target-port=80
service/demo exposed


[root@k8s1 ~]# kubectl get pod
NAME                    READY   STATUS    RESTARTS   AGE
demo-6c54f77c95-4x4m8   1/1     Running   0          57s
demo-6c54f77c95-hbrxk   1/1     Running   0          57s
demo-6c54f77c95-x5bsd   1/1     Running   0          69s

此时查看endpoint:
[root@k8s1 ~]# kubectl describe svc demo
Name:              demo
Namespace:         default
Labels:            app=demo
Annotations:       <none>
Selector:          app=demo
Type:              ClusterIP
IP Family Policy:  SingleStack
IP Families:       IPv4
IP:                10.109.224.102
IPs:               10.109.224.102
Port:              <unset>  80/TCP
TargetPort:        80/TCP
Endpoints:         10.244.1.14:80,10.244.2.10:80,10.244.2.9:80
Session Affinity:  None
Events:            <none>
[root@k8s1 ~]#


此时还不能被集群外访问,这里依然只能访问集群内的三个ip

原因:此时svc的类型是ClusterIP,我们需要改成NodePort才能在集群外访问:

SVC:k8s的一个微服务,提供pod负载均衡

[root@k8s1 ~]# kubectl get svc
NAME         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)   AGE
demo         ClusterIP   10.109.224.102   <none>        80/TCP    12m
kubernetes   ClusterIP   10.96.0.1        <none>        443/TCP   2d20h

更改svc:

kubectl edit svc demo

  type: NodePort
[root@k8s1 ~]# kubectl get svc
NAME         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE
demo         NodePort    10.109.224.102   <none>        80:30151/TCP   17m
kubernetes   ClusterIP   10.96.0.1        <none>        443/TCP        2d21h

此时发现绑定了 一个端口(端口不固定)30151

在edge访问:

11/12/13都可以访问

SVC在集群节点上的开放了端口(类似端口映射),在访问端口时就可以访问pod,通过iptables的策略实现



yaml文件(资源清单):

在K8S集群中,需要标准化操作集群,此时需要通过写yaml文件来标准化操作

这些yaml文件有统一规范写法,可以通过简单的方式认识yaml文件的格式:

apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: null
  labels:
    run: demo
  name: demo
spec:
  containers:
  - image: nginx
    name: demo
    resources: {}
  dnsPolicy: ClusterFirst
  restartPolicy: Always
status: {}

运行和删除yaml文件:

kubectl apply -f pod.yaml

kubectl delete -f pod.yaml

进行简单的改写:

apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: null
  labels:
    run: demo
  name: demo
spec:
  hostNetwork: true
  nodeSelector:
    #disktype: ssd
  containers:
  - image: nginx
    name: demo
    resources:
      limits:
        cpu: 0.2
        #100m
        memory: 256Mi
        #+i 1024cache
        #not i 1000cache
      requests:
        cpu: 100m
        memory: 100Mi
    imagePullPolicy: IfNotPresent
    #ports:
    #- name: http
    #  containerPort: 80
    #  hostPort: 80
  #- name:busybox
  #  image: busybox
  #  imagePullPolicy: IfNotPresent
  #  tty: true
  #  stdin: true

解释:

端口名称可以通过命令查看

kubectl get pod -o wide

k8s1:

k8s2:

k8s3:

QoS(容器的质量控制):

在k8s中,不能直接修改QoSclass的值,只能通过限制resources的资源来设置

设置节点标签:

#查看标签
[root@k8s1 ~]# kubectl label nodes k8s1 disktype=ssd^C
[root@k8s1 ~]# kubectl get nodes --show-labels
NAME   STATUS   ROLES                  AGE     VERSION    LABELS
k8s1   Ready    control-plane,master   2d23h   v1.23.12   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=k8s1,kubernetes.io/os=linux,node-role.kubernetes.io/control-plane=,node-role.kubernetes.io/master=,node.kubernetes.io/exclude-from-external-load-balancers=
k8s2   Ready    <none>                 2d21h   v1.23.12   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,disktype=ssd,kubernetes.io/arch=amd64,kubernetes.io/hostname=k8s2,kubernetes.io/os=linux
k8s3   Ready    <none>                 2d22h   v1.23.12   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=k8s3,kubernetes.io/os=linux


#设置标签
kubectl label nodes k8s1 disktype=ssd

访问集群内任何一个节点都可以访问到pod,通过svc暴露

共享网络栈即Pod内的容器不能使用同一个镜像(端口冲突)

hostNetwork:定义是否使用主机网络模式:

通过这个简单的yaml文件来认识和学习yaml文件的编写,以下是一些资源清单的数据类型:

https://cloud.tencent.com/developer/article/2276496

我们重点关注此类内容:


Pod生命周期:

一个pod被创建之前首先会经过初始化,初始化包括容器环境初始化和init容器初始化(可选项,一个接一个初始化),然后再启动主容器。

在主容器启动时,会有探针诊断容器是否正常运行,如果检测异常,则根据策略进行相应的执行操作。

        Pod可以包含多个容器,应用运行在这些容器里面,同时 Pod也可以有一个或多个先于应用容器启动的Init容器。

        Init容器与普通的容器非常像,除了如下两点:

        它们总是运行到完成。

        Init 容器不支持 Readiness,因为它们必须在 Pod 就绪之前运行完成,每 个Init容器必须运行成功,下一个才能够运行。

        如果 Pod 的 Init 容器失败,Kubernetes 会不断地重启该 Pod,直到 Init 容器成 功为止。然而,如果Pod对应的restartPolicy值为Never,它不会重新启动。

初始化容器可以做什么:

Init容器可以包含一些安装过程中应用容器中不存在的实用工具或个性化代码。

Init 容器可以安全地运行这些工具,避免这些工具导致应用镜像的安全性降低。

应用镜像的创建者和部署者可以各自独立工作,而没有必要联合构建一个单独的应用镜像。

Init容器能以不同于Pod内应用容器的文件系统视图运行。因此, Init容器可具有访问Secrets的权限,而应用容器不能够访问。

由于Init 容器必须在应用容器启动之前运行完成,因此 Init 容器提供了一种机制来阻塞或延迟应用容器的启动,直到满足了一组先决条件。一旦前置条件满足,Pod内的所有的应用容器会并行启动。

三种探针:

        livenessProbe:指示容器是否正在运行。如果存活探测失败,则 kubelet 会杀死容器,并且容器将受到其 重启策略 的影响。如果容器不提供存活探针,则默认状态为 Success
        readinessProbe:指示容器是否准备好服务请求。如果就绪探测失败,端点控制器将从与 Pod 匹配的所有 Service 的端点中删除该 Pod IP 地址。初始延迟之前的就绪状态默认为 Failure 。如果容器不提供就绪探针,则默认状态为 Success
        startupProbe: 指示容器中的应用是否已经启动。如果提供了启动探测 (startup probe),则禁用所有其他探测,直到它成功为止。如果启动探测失败 ,kubelet 将杀死容器,容器服从其重启策略进行重启。如果容器没有提供启动探测,则默认状态为成功Success

三种诊断方式:

探针 是由 kubelet 对容器执行的定期诊断 :
        ExecAction:在容器内执行指定命令。如果命令退出时返回码为 0 则认为
诊断成功。
        TCPSocketAction:对指定端口上的容器的 IP 地址进行 TCP 检查。如果
端口打开,则诊断被认为是成功的。
        HTTPGetAction:对指定的端口和路径上的容器的 IP 地址执行 HTTP Get
请求。如果响应的状态码大于等于 200 且小于 400 ,则诊断被认为是成功
的。
每次探测都将获得以下三种结果之一:
        成功:容器通过了诊断。
        失败:容器未通过诊断。
        未知:诊断失败,因此不会采取任何行动。
参数解释:
        initialDelaySeconds             pod启动后延迟多久进行检测
        periodSeconds                    检测的间隔时间,默认10秒
        timeoutSeconds                  检测的超时时间,默认1秒
        successThreshold               检测失败后再次判断成功的阈值,默认1次
        failureThreshold                  检测失败的重试次数,默认3次

举例init容器使用:

apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: null
  labels:
    run: demo
  name: demo
spec:
  initContainers:
    - name: init-container
      image: busybox
      command: ["/bin/sh", "-c", "until nslookup myservice.default.svc.cluster.local; do echo waiting for myservice; sleep 2; done"]
  #hostNerwork: ture
  nodeSelector:
    disktype: ssd
  containers:
  - image: nginx
    name: demo
    resources:
      limits:
        cpu: 0.2
        #100m
        memory: 256Mi
        #+i 1024cache
        #not i 1000cache
      requests:
        cpu: 100m
        memory: 100Mi
    imagePullPolicy: IfNotPresent
    #ports:
    #- name: http
    #  containerPort: 80
    #  hostPort: 80
  #- name:busybox
  #  image: busybox
  #  imagePullPolicy: IfNotPresent
  #  tty: true
  #  stdin: true

此时我们加入init容器,init解析svc是否被创建,直到解析成功为止,init容器才会退出,然后运行主容器,很明显集群内svc并没有创建,所以容器会一直处于初始化状态:

此时则需要运行一个svc

---
apiVersion: v1
kind: Service
metadata:
  name: myservice
spec:
  ports:
  - protocol: TCP
    port: 80
    targetPort: 9376

运行svc之后再看pod状态,此时running:


init容器初始化成功之后会退出

举例liveness存活探针使用:

apiVersion: v1
kind: Pod
metadata:
  labels:
    test: liveness
  name: liveness-http
spec:
  containers:
    - name: liveness
      image: nginx
      imagePullPolicy: IfNotPresent
      livenessProbe:
        tcpSocket:
          port: 8080
        initialDelaySeconds: 1    容器正常启动多长时间之后检测
        periodSeconds: 3    #监测频率
        timeoutSeconds: 1    #检测超时时间

liveness探针通过tcp的方式查看nginx的8080端口是否就绪,显然并没有就绪,通过get pod可以发现pod在被不断重启

[root@k8s1 ~]# kubectl get pod
NAME            READY   STATUS    RESTARTS   AGE
liveness-http   1/1     Running   0          6s
[root@k8s1 ~]# kubectl get pod
NAME            READY   STATUS    RESTARTS   AGE
liveness-http   1/1     Running   0          9s
[root@k8s1 ~]# kubectl get pod
NAME            READY   STATUS    RESTARTS     AGE
liveness-http   1/1     Running   1 (2s ago)   12s

此时改回80端口之后,重新apply,pod即可正常运行


readiness就绪探针举例:

apiVersion: v1
kind: Pod
metadata:
  labels:
    test: liveness
  name: liveness-http
spec:
  containers:
    - name: liveness
      image: nginx
      imagePullPolicy: IfNotPresent
      livenessProbe:
        tcpSocket:
          port: 80
        initialDelaySeconds: 1
        periodSeconds: 3
        timeoutSeconds: 1

      readinessProbe:
        httpGet:
          path: /test.html
          port: 80
        initialDelaySeconds: 1
        periodSeconds: 3
        timeoutSeconds: 1

在readness探针中,采用了httpGet的方式来诊断容器受否正常运行,此时nginx中并没有test.html页面,容器检测没有ready:

[root@k8s1 ~]# kubectl get pod
NAME            READY   STATUS    RESTARTS   AGE
liveness-http   0/1     Running   0          3m27s

使用exec进入容器内,创建test.html

[root@k8s1 ~]# kubectl exec liveness-http -- touch  /usr/share/nginx/html/test.html
[root@k8s1 ~]# kubectl get pod
NAME            READY   STATUS    RESTARTS   AGE
liveness-http   1/1     Running   0          34s

一般liveness和readness配合一起使用

如果容器无法启动,


控制器:

控制器官方文档:

Deployments | Kubernetes

Pod 的分类:

        自主式 Pod: Pod 退出后不会被创建

        控制器管理的Pod:在控制器的生命周期里,始终要维持 Pod的副本数目

控制器类型:Replication Controller和ReplicaSet(推荐使用后者)

Deployment

DaemonSet

StatefulSet

Job

CronJob(周期化)

HPA全称Horizontal Pod Autoscaler(动态弹缩)

Replication Controller和ReplicaSet:

        ReplicaSet是下一代的Replication Controller,官方推荐使用ReplicaSet

        ReplicaSet和Replication Controller的唯一区别是选择器的支持, ReplicaSet支持 新的基于集合的选择器需求。

        ReplicaSet 确保任何时间都有指定数量的 Pod 副本在运行。

        虽然ReplicaSets可以独立使用,但今天它主要被Deployments用作协调Pod创建、删除和更新的机制。

Deployment:

        Deployment为 Pod和 ReplicaSet 提供了一个申明式的定义方法。

        典型的应用场景:

                用来创建Pod和ReplicaSet

                滚动更新和回滚

                扩容和缩容

                暂停与恢复

控制器的作用是从etcd中把期望状态载入,不断向期望状态趋近

deployment适用与无状态应用

ReplicaSet控制器示例:

apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: deployment-example
spec:
  replicas: 3
#可以自定义副本数
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx
#自定义容器镜像以及版本

此时8mrxn是无主的,因为这和rs控制器所匹配的标签匹配不上

当改回标签的时候,新开的标签会被优先回收

在rs控制器get all时:


在使用deployment控制器时,可以进行更新和回滚

deployment控制器示例:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: deployment-example
spec:
  replicas: 6
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: myapp:v1
#修改版本

关系:deployment控制器创建rs控制器->pod

deployment控制的rs控制器相当于控制版本

通过修改yaml文件实现版本迭代:

原来的rs控制器没有删掉是为了快速回滚

删除之后回滚速度会下降:


滚动更新:

示例:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: deployment-example
spec:
  minReadySeconds: 3
#最短就绪时间
  strategy:
    rollingUpdate:
      maxSurge: 2
#最大峰值
      maxUnavailable: 0
#最大不可用
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: myapp:v2

运行yaml文件之前,我们可以查看参数详情:

kubectl explain deployment.spec.strategy.rollingUpdate

最大峰值表示每一次更新pod数量最多不超过该值

最大不可用:

在修改最大不可用和最大峰值之后,重新运行yaml

显示效果太快无法观察,除了使用参数,还可以使用init容器来阻塞和用探针来减慢容器的running过程,以便观察结果

查看pod详细信息:

kubectl get pod deployment-example-XXX -o yaml

暂停、回复Deployment的上限过程:

kubectl rollout pause deployment deployment-example

此时pod正常运行,但是版本未更新

查看deployment上线过程

恢复上线:

kubectl rollout resume deployment deployment-example

DaemonSet控制器:

        DaemonSet 确保全部(或者某些)节点上运行一个 Pod 的副本。当有节点加入集群时, 也会为他们新增一个 Pod 。当有节点从集群移除时,这些Pod 也会被回收。删除 DaemonSet 将会删除它创建的所有 Pod
例如在搭建集群事所使用的kube-flannel.yml网络插件使用的就是此类型控制器。
DaemonSet 的典型用法:
        在每个节点上运行集群存储 DaemonSet ,例如 glusterd ceph
        在每个节点上运行日志收集 DaemonSet ,例如 fluentd logstash
        在每个节点上运行监控 DaemonSet ,例如 Prometheus Node Exporter、 zabbix agent等。
        一个简单的用法是在所有的节点上都启动一个 DaemonSet ,将被作为每种类型的 daemon 使用。
        一个稍微复杂的用法是单独对每种 daemon 类型使用多个 DaemonSet ,但具有不同的标志, 并且对不同硬件类型具有不同的内存、CPU 要求。

示例:

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: daemonset-example
  labels:
    k8s-app: zabbix-agent
spec:
  selector:
    matchLabels:
      name: zabbix-agent
  template:
    metadata:
      labels:
        name: zabbix-agent
    spec:
      containers:
      - name: zabbix-agent
        image: nginx
     # tolerations:
     # - operator: Exists
     #   effect: NoSchedule
#污点

daemonset一般被调度在worker节点上,master节点一般负责核心组件,不参与调度

此时只有k8s2和k8s3被调度:

去掉注释之后,重新运行之后,此时k8s1也参与调度:

污点 

容忍

job控制器:

执行批处理任务,仅执行一次任务,保证任务的一个或多个 Pod 成功结束
Job用来做离线任务

示例:

apiVersion: batch/v1
kind: Job
metadata:
  name: pi
spec:
  template:
    spec:
      containers:
      - name: pi
        image: perl:5.34.0
        command: ["perl",  "-Mbignum=bpi", "-wle", "print bpi(2000)"]
      restartPolicy: Never
  backoffLimit: 4

此时Job运行完毕之后就终止

查看Job信息:

kubectl logs pi-t5ts6

查看该pod由谁创建:

创建多个任务:

cat busybox-job.yaml
apiVersion: batch/v1
kind: Job
metadata:
  name: busybox-job
spec:
  parallelism: 1
  completions: 5
#需要执行5次任务才算完成
  template:
    spec:
      containers:
      - name: busybox
        image: busybox:latest
        command: [ "/bin/sh", "-c", "sleep 20s" ]
      restartPolicy: OnFailure

三种Job的执行方式:

CronJob控制器:

Cron Job 创建基于时间调度的 Jobs
一个 CronJob 对象就像 crontab (cron table) 文件中的一行,它用 Cron 格式
进行编写,并周期性地在给定的调度时间执行 Job.
示例:
apiVersion: batch/v1beta1
kind: CronJob
metadata:
  name: cronjob-example
spec:
  schedule: "* * * * *"
  jobTemplate:
    spec:
      template:
        spec:
          containers:
          - name: cronjob
            image: busybox
            args:
            - /bin/sh
            - -c
            - date; echo Hello from k8s cluster
          restartPolicy: OnFailure

关系: CronJob --> Job --> Pod

此时查看的是Job控制器:

Job控制器由CronJob创建

Pod由Job控制器创建:


服务Servie(SVC):

        Service可以看作是一组提供相同服务的 Pod 对外的访问接口。借助 Service ,应用可以方便地实现服务发现和负载均衡。
        service默认只支持 4 层负载均衡能力,没有 7 层功能。(可以通过 Ingress 实现和扩展)
service 的类型:
        ClusterIP:默认值, k8s 系统给 service 自动分配的虚拟 IP ,只能在集群内部访问。
        NodePort:将 Service通过指定的Node上的端口暴露给外部,访问任意一个NodeIP:nodePort都将路由到 ClusterIP。
        LoadBalancer:在 NodePort 的基础上,借助 cloud provider 创建一个外部的负载均
衡器,并将请求转发到 <NodeIP>:NodePort ,此模式只能在云服务器上使用。
        ExternalName:将服务通过 DNS CNAME 记录方式转发到指定的域名(通过
spec.externlName 设定)
Service 是由 kube-proxy 组件,加上 iptables 来共同实现的
kube-proxy 通过 iptables 处理 Service 的过程,需要在宿主机上设置相当多的iptables规则,如果宿主机有大量的 Pod ,不断刷新 iptables 规则,会消耗大量的 CPU资源。
IPVS 模式的 service ,可以使 K8s 集群支持更多量级的 Pod
开启 kube-proxy ipvs 模式:
 
# yum install -y ipvsadm

//所有节点安装
 kubectl edit cm kube-proxy -n kube-system

//修改IPVS模式

mode: "ipvs"

kubectl get pod -n kube-system |grep kube-proxy | awk '{system("kubectl delete pod "$1" -n kube-system")}'

//更新kube-proxy pod

开启之后,k8s可以支持更多的pod数量,也可以降低cpu资源消耗

IPVS 模式下, kube-proxy 会在 service 创建后,在宿主机上添加一个虚拟网卡: kube-ipvs0,并分配 service IP:
kube-proxy 通过 linux IPVS 模块,以 rr 轮询方式调度 service 中的 Pod:
        k8s通过 CNI 接口接入其他插件来实现网络通讯。目前比较流行的插件有 flannel calico 等。
        CNI插件存放位置: # cat /etc/cni/net.d/10-flannel.conflist
插件使用的解决方案如下:
        虚拟网桥,虚拟网卡,多个容器共用一个虚拟网卡进行通信。
        多路复用:MacVLAN ,多个容器共用一个物理网卡进行通信。
        硬件交换:SR-LOV,一个物理网卡可以虚拟出多个接口,这个性能最好。
容器间通信:同一个 pod 内的多个容器间的通信,通过 lo 即可实现;
pod 之间的通信:
        同一节点的pod 之间通过 cni 网桥转发数据包。
        不同节点的pod 之间的通信需要网络插件支持。
        pod和 service 通信 : 通过 iptables ipvs 实现通信, ipvs 取代不了 iptables ,因为 ipvs 只能做负载均衡,而做不了nat 转换。
pod 和外网通信: iptables MASQUERADE
Service 与集群外部客户端的通信;( ingress nodeport loadbalancer
Flannel vxlan 模式跨主机通信原理:

        VXLAN,即 Virtual Extensible LAN (虚拟可扩展局域网),是 Linux 本身支持的一网种网络虚拟化技术。VXLAN 可以完全在内核态实现封装和解封装工作,从而通过“隧道”机制,构建 出覆盖网络(Overlay Network )。
        VTEP:VXLAN Tunnel End Point (虚拟隧道端点),在 Flannel VNI 的默认值是 1 ,这也是为什么宿主机的VTEP 设备都叫 flannel.1 的原因。
        Cni0: 网桥设备,每创建一个pod 都会创建一对 veth pair 。其中一端是 pod 中的 eth0 ,另一端是Cni0 网桥中的端口(网卡)。
        Flannel.1: TUN设备( 虚拟网卡 ) ,用来进行 vxlan 报文的处理(封包和解包)。不同 node 之间的pod 数据流量都从 overlay 设备以隧道的形式发送到对端。
        Flanneld:flannel 在每个主机中运行 flanneld 作为 agent ,它会为所在主机从集群的网络地址空间中,获取一个小的网段subnet ,本主机内所有容器的 IP 地址都将从中分配。同时
Flanneld 监听 K8s 集群数据库,为 flannel.1 设备提供封装数据时必要的 mac ip 等网络数据信
息。
flannel网络原理:
        当容器发送IP 包,通过 veth pair 发往 cni 网桥,再路由到本机的 flannel.1 设备进行处理。VTEP设备之间通过二层数据帧进行通信,源 VTEP 设备收到原始 IP 包后,在上面加上一个目的MAC 地址,封装成一个内部数据帧,发送给目的 VTEP 设备。
        内部数据桢,并不能在宿主机的二层网络传输,Linux 内核还需要把它进一步封装成为宿主机的一个普通的数据帧,承载着内部数据帧通过宿主机的eth0 进行传输。
        Linux会在内部数据帧前面,加上一个VXLAN 头, VXLAN 头里有一个重要的标志叫VNI,它是 VTEP 识别某个数据桢是不是应该归自己处理的重要标识。
        flannel.1设备只知道另一端flannel.1 设备的 MAC 地址,却不知道对应的宿主机地址是什么。在linux 内核里面,网络设备进行转发的依据,来自 FDB 的转发数据库,这个flannel.1网桥对应的 FDB 信息,是由 flanneld 进程维护的。
        linux内核在 IP 包前面再加上二层数据帧头,把目标节点的 MAC 地址填进去, MAC 地址从宿主机的ARP 表获取。
        此时flannel.1设备就可以把这个数据帧从 eth0 发出去,再经过宿主机网络来到目标节
点的 eth0 设备。目标主机内核网络栈会发现这个数据帧有 VXLAN Header ,并且 VNI为1, Linux内核会对它进行拆包,拿到内部数据帧,根据VNI的值,交给本机flannel.1设备处理, flannel.1 拆包,根据路由表发往 cni 网桥,最后到达目标容器
在同一VLAN中,使用host-gw主机网关:
kubectl -n kube-flannel edit cm kube-flannel-cfg

在不同VALN中,使用VXLAN进行封装

创建service(ClusterIP模式):
可以使用域名和IP地址来访问svc
apiVersion: v1
kind: Service
metadata:
  name: svc1
spec:
  ports:
  - port: 80
    protocol: TCP
    targetPort: 80
  selector:
    app: nginx
  type: ClusterIP

在拉起控制器的yaml文件(指定副本数为3即可)和svc的yaml文件之后

我们可以通过dig来查询集群内svc的IP地址

[root@k8s1 ~]# dig -t A svc1.default.svc.cluster.local. @10.96.0.10

#svc1是控制器的名称,default是控制器所在的namespace,后面的svc.cluster.local是固定写法
#@10.96.0.10需要加上,否则查询出的是虚拟机的解析

; <<>> DiG 9.9.4-RedHat-9.9.4-72.el7 <<>> -t A svc1.default.svc.cluster.local. @10.96.0.10
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 50926
;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; WARNING: recursion requested but not available

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;svc1.default.svc.cluster.local.        IN      A

;; ANSWER SECTION:
svc1.default.svc.cluster.local. 30 IN   A       10.98.187.234

此时看到svc被解析出来

;; Query time: 1 msec
;; SERVER: 10.96.0.10#53(10.96.0.10)
;; WHEN: Mon Jan 22 17:55:41 CST 2024
;; MSG SIZE  rcvd: 105
[root@k8s1 ~]# kubectl get svc
NAME         TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE
kubernetes   ClusterIP   10.96.0.1       <none>        443/TCP   8d
svc1         ClusterIP   10.98.187.234   <none>        80/TCP    10m

再通过创建的pod来访问:

kubectl run demo -it --rm --image=busyboxplus

[root@k8s1 ~]# kubectl run demo -it --rm --image=busyboxplus
If you don't see a command prompt, try pressing enter.
/ # nslookup svc1.default.svc.cluster.local.
Server:    10.96.0.10
Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local

Name:      svc1.default.svc.cluster.local.
Address 1: 10.98.187.234 svc1.default.svc.cluster.local
/ # curl svc1
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
/ # cat /etc/resolv.conf
nameserver 10.96.0.10
search default.svc.cluster.local svc.cluster.local cluster.local
options ndots:5
/ #  nslookup kubernetes
Server:    10.96.0.10
Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local

Name:      kubernetes
Address 1: 10.96.0.1 kubernetes.default.svc.cluster.local
/ # Session ended, resume using 'kubectl attach demo -c demo -i -t' command when the pod is running
pod "demo" deleted
[root@k8s1 ~]# kubectl run demo -it --rm --image=busyboxplus
If you don't see a command prompt, try pressing enter.
/ # nslookup kube-dns.kube-system
Server:    10.96.0.10
Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local

Name:      kube-dns.kube-system
Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local
[root@k8s1 ~]# kubectl get svc -A
NAMESPACE     NAME         TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)                  AGE
default       kubernetes   ClusterIP   10.96.0.1       <none>        443/TCP                  8d
default       svc1         ClusterIP   10.98.187.234   <none>        80/TCP                   13m
kube-system   kube-dns     ClusterIP   10.96.0.10      <none>        53/UDP,53/TCP,9153/TCP   8d
无头服务:
Headless Service “ 无头服务 ”:

Headless Service 不需要分配一个 VIP ,而是直接以 DNS 记录的方式解析出被代理 Pod的IP 地址。
域名格式: $(servicename).$(namespace).svc.cluster.local

此时解到的IP地址直接解到三个pod上且负载均衡

此时不需要解析IP直接访问到pod的IP地址

NodePort方式:

可以通过外部访问

nodeprt方式需要注意,一个节点访问一个端口

创建一个svc2的yaml,delete原来的svc文件

[root@k8s1 ~]# cat svc2.yaml
apiVersion: v1
kind: Service
metadata:
  name: svc2
spec:
  ports:
  - port: 80
    protocol: TCP
    targetPort: 80
  selector:
    app: nginx
  type: NodePort

运行之后可以看到svc2的类型是nodeport:

此时就可以通过访问集群任意节点加端口来访问pod:

如果我们指定端口为33333:

此时再运行svc2.yaml:

报错超过有效端口范围,此时修改k8s的默认端口范围:

vim /etc/kubernetes/manifests/kube-apiserver.yaml

此时kubelet会自动重启apiserver:

短暂等待之后即可连上,如果上时间连不上,检查范围是否书写有误:

此时再运行svc2.yaml文件:

这样可以解决pod过多而端口不够使用

LoadBalancer(metallb):

同样可以通过外部访问

从外部访问 Service 的第二种方式,适用于公有云上的 Kubernetes 服务。这时候,你可以指定一个 LoadBalancer 类型的 Service
service 提交后, Kubernetes 就会调用 CloudProvider 在公有云上为你创建一个负载均衡服务,并且把被代理的 Pod IP 地址配置给负载均衡服务做后端。
在云平台时,我们通过LoadBalancer提供的负载均衡地址,可以直接访问到pod的IP地址:
在使用虚拟机搭建集群时,环境为裸金属服务器集群,此时用metallb来进行配置
首先需要创建目录:
[root@k8s1 ~]# mkdir metallb

拉取yaml文件:

没有wget则需要下载,可能需要多拉取几次

wget https://raw.githubusercontent.com/metallb/metallb/v0.13.7/config/manifests/metallb-native.yaml

对于metallb-native.yaml,我们需要更改镜像拉取位置:

image: metallb/controller:v0.13.7

image: metallb/speaker:v0.13.7

此时我们登录harbor仓库,创建metallb库:

然后在harbor节点拉取镜像:
docker pull quay.io/metallb/controller:v0.13.7

docker pull quay.io/metallb/speaker:v0.13.7

然后给镜像打标签,上传镜像:

根据官网复制yaml文件:
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
  name: first-pool
  namespace: metallb-system
spec:
  addresses:
  - 172.25.0.100-172.25.0.200
网络地址段

---
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
  name: example
  namespace: metallb-system
#如果有多个地址池
spec:
  ipAddressPools:
  - first-pool
#则可以从ipAddressPools中进行选择

编写好之后运行,查看svc:
此时svc3有了外部IP,我们可以通过外部IP而不用加端口号来进行访问

ExternalName:

从外部访问的第三种方式 
apiVersion: v1
kind: Service
metadata:
  name: svc4
spec:
  type: ExternalName
  externalName: www.baidu.com

对于集群之间的相互访问,而外部的集群访问不稳定会随之而更改,此时需要在稳定的集群内部做出最小的改变来访问其他集群

对于经常改动的,直接更改externalName就可以。

Ingress:

        一种全局的、为了代理不同后端 Service 而设置的负载均衡服务,就是 Kubernetes 里的Ingress 服务。
        Ingress由两部分组成: Ingress controller Ingress 服务。
        Ingress Controller 会根据你定义的 Ingress 对象,提供对应的代理能力。业界常用的各种
反向代理项目,比如 Nginx HAProxy Envoy Traefik 等,都已经为 Kubernetes 专门维
护了对应的 Ingress Controller
首先访问ingress官网: Welcome - Ingress-Nginx Controller
我们先创建ingress目录,wget下来这个yaml文件,不要运行
mkdir ingress

wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.4.0/deploy/static/provider/baremetal/deploy.yaml

我们使用1.4.0版本即可,如果拉取不下来记得多拉取几次

拉取下来之后更改镜像位置,一共需要拉取两个镜像,更改位置有两处:

改成如图所示:
之后在harbor拉取1.4.0版本的镜像:
docker pull echolixiaopeng/ingress-nginx-controller:v1.4.0

docker pull xin053/kube-webhook-certgen:v20220916-gd32f8c343

在harbor仓库新建ingress-nginx仓库设为公共,然后更改标签和上传镜像

上传成功之后检查:
然后运行yaml
root@k8s1 ingress]# kubectl apply -f deploy.yaml

[root@k8s1 ingress]# kubectl get all -n ingress-nginx
NAME                                           READY   STATUS      RESTARTS      AGE
pod/ingress-nginx-admission-create-ch9bc       0/1     Completed   0             15h
pod/ingress-nginx-admission-patch-lm5dz        0/1     Completed   0             15h
pod/ingress-nginx-controller-5d67f9886-4zv6j   1/1     Running     1 (14h ago)   15h

#主要看pod/ingress-nginx-controller-5d67f9886-4zv6j是否running
#pod/ingress-nginx-controller-5d67f9886-4zv6j实际封装的就是nginx

NAME                                         TYPE           CLUSTER-IP       EXTERNAL-IP    PORT(S)                      AGE
service/ingress-nginx-controller             LoadBalancer   10.104.119.129   172.25.0.100   80:42838/TCP,443:61580/TCP   15h
service/ingress-nginx-controller-admission   ClusterIP      10.107.219.243   <none>         443/TCP                      15h

NAME                                       READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/ingress-nginx-controller   1/1     1            1           15h

NAME                                                 DESIRED   CURRENT   READY   AGE
replicaset.apps/ingress-nginx-controller-5d67f9886   1         1         1       15h

NAME                                       COMPLETIONS   DURATION   AGE
job.batch/ingress-nginx-admission-create   1/1           6s         15h
job.batch/ingress-nginx-admission-patch    1/1           7s         15h

我们可以设置svc的暴露方式,通过mrtallb目录下的config.yaml文件从LousterIP改为Load Balancer:

此时通过端口或负载均衡ip都可以访问pod
此时创建ingress策略:
需要注意的是svc和ingress都要在同一default下
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: demo-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
#rewrite-target:  重定向到跟路径

spec:
  ingressClassName: nginx
  rules:
  - http:
      paths:
      - path: /foo
        pathType: Prefix
        backend:
          service:
            name: svc1
            port:
              number: 80

      paths:
      - path: /bar
        pathType: Prefix
        backend:
          service:
            name: svc2
            port:
              number: 80

创建第二个服务以实现效果:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: deployment-myapp
spec:
  #minReadySeconds: 3
  strategy:
    rollingUpdate:
      maxSurge: 2
      maxUnavailable: 0
  replicas: 3
  selector:
    matchLabels:
      app: myapp
  template:
    metadata:
      labels:
        app: myapp
    spec:
      containers:
      - name: myapp
        image: myapp:v2

---
apiVersion: v1
kind: Service
metadata:
  name: svc2
spec:
  ports:
  - port: 80
    protocol: TCP
    targetPort: 80
  selector:
    app: myapp
  type: ClusterIP

此时运行第二个deployment,在harbor查看效果:

我们再通过不同域名来访问svc控制的pod:
修改更改的ingress.yaml:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: demo-ingress
  #annotations:
  #  nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  ingressClassName: nginx
  rules:
  - host: www1.westos.org
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: svc1
            port:
              number: 80

  - host: www2.westos.org
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: svc2
            port:
              number: 80

在基于域名访问时,需要在harbor节点加上解析,否则访问不到:

127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
172.25.0.10 harbor reg.westos.org
172.25.0.11 k8s1
172.25.0.12 k8s2
172.25.0.13 k8s3
172.25.0.14 k8s4
172.25.0.15 k8s5
172.25.0.16 k8s6
172.25.0.100 www1.westos.org www2.westos.org

        用DaemonSet结合nodeselector来部署ingress-controller到特定的node上,然后使用HostNetwork直接把该pod与宿主机node的网络打通,直接使用宿主机的80/443端口就能访问服务

        优点是整个请求链路最简单,性能相对NodePort模式更好。

        缺点是由于直接利用宿主机节点的网络和端口,一个node只能部署一个ingress-controller pod。

        比较适合大并发的生产环境使用

#修改ingress controller部署文件
vim mandatory.yaml

kind: DaemonSet //改为DaemonSet控制器
  replicas: 1 //删除replicas
hostNetwork: true //使用HostNetwork
nodeSelector: //修改节点选择
 type: "ingress"

设置ingress controller节点的标签
kubectl label nodes server6 type=ingress

TLS配置:

创建证书:

注意创建的证书和svc或者其他,需要调用时,他们应该在同一域(namespace)内

openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:2048 -keyout tls.key -out tls.crt -subj "/CN=nginxsvc/O=nginxsvc"

#移动到ingress下

mv tls.crt  tls.key ingress/

[root@k8s1 ~]# kubectl get secrets
NAME                  TYPE                                  DATA   AGE
basic-auth            Opaque                                1      3h16m
default-token-67c64   kubernetes.io/service-account-token   3      9d
tls-secret            kubernetes.io/tls                     2      3h32m

创建新的yaml文件来认证和加密:

官网:Welcome - Ingress-Nginx Controller

加密:

vim ingress-https.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ingress-https
  #annotations:
  #  nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  tls:
    - hosts:
      - www1.westos.org
      secretName: tls-secret
  ingressClassName: nginx
  rules:
  - host: www1.westos.org
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: svc1
            port:
              number: 80

此时:
curl -I www1.westos.org

curl -k https://www1.westos.org

#-k 不校验证书

认证:
yum install -y httpd-tools.x86_64
htpasswd -Bc auth admin
admin

将资源创建到集群中:

kubectl create secret generic basic-auth --from-file=auth

kubectl get secret basic-auth -o yaml

查看

继续写入配置:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ingress-https
  annotations:

    nginx.ingress.kubernetes.io/auth-type: basic
#激活认证
    nginx.ingress.kubernetes.io/auth-secret: basic-auth
#使用secret
    nginx.ingress.kubernetes.io/auth-realm: 'Authentication Required - admin'
#输出信息
   # nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  tls:
    - hosts:
      - www1.westos.org
      secretName: tls-secret
  ingressClassName: nginx
  rules:
  - host: www1.westos.org
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: svc1
            port:
              number: 80

重新运行,然后再harbor访问,此时需要输入用户名和密码:

重定向:

在ingress-https.yaml中加入:

重定向的规则

curl命令不支持url重定向:
curl -I
-I, --head
              (HTTP/FTP/FILE) Fetch the HTTP-header only! HTTP-servers feature the command HEAD which this uses to get nothing but the header of  a  document.  When used on an FTP or FILE file, curl displays the file size and last modification time only.

金丝雀发布(灰度发布):

接管流量有三种方式可选择:
header->cookie->weight
header灰度:通过指定特定标签来访问
        通过Annotaion扩展
        创建灰度ingress,配置灰度头部key以及value
        灰度流量验证完毕后,切换正式导入到新版本
这种方式我们需要开启deployment和两个svc
普通访问:
加上特定key:
基于权重weight:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: myapp-v1-ingress
spec:
  ingressClassName: nginx
  rules:
  - host: myapp.westos.org
    http:
      paths:
      - pathType: Prefix
        path: /
        backend:
          service:
            name: svc1
            port:
              number: 80

---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    nginx.ingress.kubernetes.io/canary: "true"
    #nginx.ingress.kubernetes.io/canary-by-header: stage
    #nginx.ingress.kubernetes.io/canary-by-header-value: gray
    nginx.ingress.kubernetes.io/canary-weight: "40"
#权重
    nginx.ingress.kubernetes.io/canary-weightr-total: "100"
#总量
  name: myapp-v2-ingress
spec:
  ingressClassName: nginx
  rules:
  - host: myapp.westos.org
    http:
      paths:
      - pathType: Prefix
        path: /
        backend:
          service:
            name: svc2
            port:
              number: 80

使用脚本来查流量分布情况:

脚本:
#!/bin/bash

v1=0
v2=0

for (( i=0; i<100; i++))
do
    response=`curl -s myapp.westos.org |grep -c v1`

    v1=`expr $v1 + $response`
    v2=`expr $v2 + 1 - $response`

done

echo "v1:$v1, v2:$v2"


Calico网络插件:

calico 简介:
        flannel实现的是网络通信, calico 的特性是在 pod 之间的隔离。
        通过BGP 路由,但大规模端点的拓扑计算和收敛往往需要一定的时间和计算资源。
        纯三层的转发,中间没有任何的NAT overlay ,转发效率最好。
        Calico 仅依赖三层路由可达。 Calico 较少的依赖性使它能适配所有 VM、 Container、白盒或者混合环境场景。
calico网络架构:
        Felix:监听ECTD中心的存储获取事件,用户创建pod后,Felix负责将其网卡、IP、MAC都设 置好,然后在内核的路由表里面写一条,注明这个IP应该到这张网卡。同样如果用户制定了隔 离策略,Felix同样会将该策略创建到ACL中,以实现隔离。
        BIRD:一个标准的路由程序,它会从内核里面获取哪一些IP的路由发生了变化,然后通过标准 BGP的路由协议扩散到整个其他的宿主机上,让外界都知道这个IP在这里,路由的时候到这里来。
        IPIP工作模式:适用于互相访问的pod不在同一个网段中,跨网段访问的场景。
        BGP工作模式:适用于互相访问的pod在同一个网段,适用于大型网络。
NetworkPolicy策略模型:控制某个namespace下的pod的网络出入站规则

参照官网,我们使用的是3.24.3版本,首先先获取yaml文件:

wget https://raw.githubusercontent.com/projectcalico/calico/v3.24.3/manifests/calico.yaml

修改镜像文件位置为calico,然后通过harbor仓库拉取镜像,修改标签并上传,做好本地化处理。

一共有五处,两处cni,两处node,一处controllers

然后拉取镜像:

docker pull docker.io/calico/kube-controllers:v3.24.3
docker pull docker.io/calico/cni:v3.24.3
docker pull docker.io/calico/node:v3.24.3

修改标签:

images|grep calico| awk '{system("docker tag "$1":"$2" reg.westos.org/"$1":"$2"  ")}'

上传harbor之前我们需要建立calico仓库:

images|grep calico| awk '{system("docker tag "$1":"$2" reg.westos.org/"$1":"$2"  ")}'

docker images|grep calico|grep -v ^calico| awk '{system (" docker push "$1":"$2" ")}'

calico也是一种和flannel类似的网络插件,在运行calico之前,我们需要去除flannel插件:

kubectl delete -f kube-flannel.yml

删除三个节点的flannel文件,注意三个节点都要删除:

rm -rf /etc/cni/net.d/10-flannel.conflist

此时再运行calico插件:

kubectl apply -f calico.yaml

[root@k8s1 calico]# kubectl get pod -n kube-system
NAME                                       READY   STATUS    RESTARTS       AGE
calico-kube-controllers-58c694dbfc-rftjk   1/1     Running   1 (15h ago)    17h
calico-node-ctqpc                          1/1     Running   1 (15h ago)    17h
calico-node-q5p4h                          1/1     Running   1 (41m ago)    17h
calico-node-wk4dw                          1/1     Running   1 (15h ago)    17h
coredns-7b56f6bc55-9kjf8                   1/1     Running   20 (15h ago)   10d
coredns-7b56f6bc55-rrrjt                   1/1     Running   21 (15h ago)   10d
etcd-k8s1                                  1/1     Running   16 (15h ago)   10d
kube-apiserver-k8s1                        1/1     Running   4 (15h ago)    44h
kube-controller-manager-k8s1               1/1     Running   19 (15h ago)   10d
kube-proxy-8skn5                           1/1     Running   3 (15h ago)    43h
kube-proxy-f7hh9                           1/1     Running   3 (41m ago)    43h
kube-proxy-lphn7                           1/1     Running   4 (15h ago)    43h
kube-scheduler-k8s1                        1/1     Running   20 (15h ago)   10d

calicorunning之后根据了k8s官网来书写网络策略:

网络策略 | Kubernetes

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: test-network-policy
  namespace: default
spec:
  podSelector:
#通过podSelector来选择控制对象
    matchLabels:
      app: nginx
#标签
  policyTypes:
    - Ingress
#这里做入栈控制为主
  ingress:
    - from:
        #- ipBlock:
        #    cidr: 172.17.0.0/16
        #    except:
        #      - 172.17.1.0/24
        #- namespaceSelector:
        #    matchLabels:
        #      project: test
        - podSelector:
            matchLabels:
              role: frontend
      ports:
        - protocol: TCP
          port: 80

当我们只使用

解释:此时的networkpolicy控制的pod是标签带有nginx的,对于该pod需要访问的pod具有

role=frontend标签才可以

此时:

此时demo是没有role=frontend这个标签的,所以在访问example这个pod时,无法访问,但是在访问myapp这个pod时,networkpolicy并没有控制这个pod的规则 ,所以可以正常访问

当我们给demo加上标签时:


但是此时作为其他namespace的pod是无法访问的:

如果需要其他pod也可以访问到控制的pod,我们需要调整:

这里是两个列表的规则,满足其一即可访问pod。

重新运行,然后在新建的test namespace中运行busybosplus:

此时我们在test这个namespace中,由于test带有project=test这个标签,所以test内的所有pod都可以访问networkpolicy控制的pod


此时我们再次修改:

这里空色部分表示且,意为属于一个列表中的两条规则,需要同时满足

此时运行policy之后:

意为不仅要是namespace带有project=test,还要pod带有role=frontend才可以访问networkpolicy控制的pod,之前我对demo加上role=frontend了标签。所以这里可以成功访问

当我们去掉demo的标签之后(去掉标签可以通过命令执行,也可以通过edit来修改而热生效):

  • 15
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值