首页 > 其他分享 >云原生第四周--kubernetes组件详解(下)

云原生第四周--kubernetes组件详解(下)

时间:2023-05-25 16:56:17浏览次数:41  
标签:容器 name kubernetes -- nginx 详解 myapp myserver Pod

Configmap

ConfigMap 是一种 API 对象,用来将非机密性的数据保存到键值对中。使用时, Pods 可以将其用作环境变量、命令行参数或者存储卷中的配置文件。
ConfigMap 将你的环境配置信息和 容器镜像 解耦,便于应用配置的修改。

使用场景:

  • 通过Configmap给pod定义全局环境变量
  • 通过Configmap给pod传递命令行参数,如mysql -u -p中的账户名密码可以通过Configmap传递。
  • 通过Configmap给pod中的容器服务提供配置文件,配置文件以挂载到容器的形式使用。

注意事项:

  • Configmap需要在pod使用它之前创建。
  • pod只能使用位于同一个namespace的Configmap,及Configmap不能夸namespace使用。
  • 通常用于非安全加密的配置场景。
  • Configmap通常是小于1MB的配置。

使用configmap提供配置文件的yaml

apiVersion: v1
kind: ConfigMap  #利用configmap提供nginx配置
metadata:
  name: nginx-config  #configmap卷名称,后面会以此名称调用configmap卷
data:
 default: | ##item名称,作为key被调用
    server {
       listen       80;
       server_name  www.mysite.com;
       index        index.html index.php index.htm;

       location / {
           root /data/nginx/html;
           if (!-e $request_filename) {
               rewrite ^/(.*) /index.html last;
           }
       }
    }


---
#apiVersion: extensions/v1beta1
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  replicas: 1
  selector:
    matchLabels:
      app: ng-deploy-80
  template:
    metadata:
      labels:
        app: ng-deploy-80
    spec:
      containers:
      - name: ng-deploy-80
        image: nginx:1.20.0
        ports:
        - containerPort: 80
        volumeMounts:
        - mountPath: /data/nginx/html # nfs卷
          name: nginx-static-dir
        - name: nginx-config   #调用configmap卷
          mountPath: /etc/nginx/conf.d
      volumes:
      - name: nginx-static-dir
        nfs:
          server: 192.168.110.184
          path: /data/k8sdata/nginx
      - name: nginx-config
        configMap:
          name: nginx-config
          items:
             - key: default
               path: mysite.conf  #将value保存在mysite.conf中

---
apiVersion: v1
kind: Service
metadata:
  name: ng-deploy-80
spec:
  ports:
  - name: http
    port: 81
    targetPort: 80
    nodePort: 30019
    protocol: TCP
  type: NodePort
  selector:
    app: ng-deploy-80

该文件生成了一个configmap卷,一个svc,一个挂载了该configmap卷的deployment控制器
在nfs服务存储上添加index.html
image

进入pod,找到configmap挂载目录

image
可以看到mysite.conf文件

查看容器中nfs挂载目录
image

将挂载目录include到nginx.conf中

image

将svc地址配置到负载均衡器中
image

image

修改宿主机host文件 添加域名 测试
image

image

使用configmap提供环境变量的yaml

apiVersion: v1
kind: ConfigMap

metadata:
  name: nginx-config
data:
  username: "user1"     ##  key和value
  password: "12345678"  ##   key和value


---
#apiVersion: extensions/v1beta1
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  replicas: 1
  selector:
    matchLabels:
      app: ng-deploy-80
  template:
    metadata:
      labels:
        app: ng-deploy-80
    spec:
      containers:
      - name: ng-deploy-80
        image: nginx
        env:       
        - name: MY_USERNAME 
          valueFrom:
            configMapKeyRef:
              name: nginx-config
              key: username
        - name: MY_PASSWORD    ##env变量名称
          valueFrom:
            configMapKeyRef:
              name: nginx-config
              key: password
        ######
        - name: "password"  #直接传递环境变量 生产中一边使用这种方式
          value: "123456"
        ports:
        - containerPort: 80

创建configmap和pod后, 进入pod查看环境变量

image
可以看到两种不通方式传递环境变量的key_value

修改configmap.yaml 修改环境变量
image

重新apply 进入容器 发现容器中的环境变量没有变化
image

得出结论,configmap修改后,需要重建容器,配置才能更改

Secret

Secret 是一种包含少量敏感信息例如密码、令牌或密钥的对象。 这样的信息可能会被放在 Pod 规约中或者镜像中。 使用 Secret 意味着你不需要在应用程序代码中包含机密数据。
由于创建 Secret 可以独立于使用它们的 Pod, 因此在创建、查看和编辑 Pod 的工作流程中暴露 Secret(及其数据)的风险较小。 Kubernetes 和在集群中运行的应用程序也可以对 Secret 采取额外的预防措施, 例如避免将机密数据写入非易失性存储。
Secret 类似于 ConfigMap 但专门用于保存机密数据。

注意:
Secret 的名称必须是合法的 DNS 子域名。

每个Secret的大小最多为1MiB,主要是为了避免用户创建非常大的Secret进而导致API服务器和kubelet内存耗尽,不过创建很多小的Secret也可能耗尽内存,可以使用资源配额来约束每个名字空间中Secret的个数。

在通过yaml文件创建secret时,可以设置data或stringData字段,data和stringData字段都是可选的,data字段中所有键值都必须是base64编码的字符串,如果不希望执行这种 base64字符串的转换操作,也可以选择设置stringData字段,其中可以使用任何非加密的字符串作为其取值。

Pod 可以用三种方式的任意一种来使用 Secret:

  • 作为挂载到一个或多个容器上的卷 中的文件(crt文件、key文件)。
  • 作为容器的环境变量。
  • 由 kubelet 在为 Pod 拉取镜像时使用(与镜像仓库的认证)。

kubernetes可支持的不同的secret类型

image

使用Sercet-Opaqu提供认证

可以定义任意数据

将用户名和密码base64加密方式显示
image

加密(data)方式sercet的yaml文件

apiVersion: v1
kind: Secret
metadata:
  name: mysecret-data
  namespace: myserver
type: Opaque
data:           #data方式,key和value要用base64加密格式保存 若不是则会报错
  user: YWRtaW4K  
  password: MTIzNDU2Cg==

明文形式(stringdata)sercet的yaml文件

apiVersion: v1
kind: Secret
metadata:
  name: mysecret-stringdata
  namespace: myserver
type: Opaque
stringData:   #stringData方式,用明文保存
  user: 'admin'
  password: '123456'

kubectl apply -f 1-secret-Opaque-data.yaml
kubectl apply -f 2-secret-Opaque-stringData.yaml

通过查询secet可以看到用户名密码分别被加密和明文方式保存;
image

image

如何挂载这些用户名密码,需要我们创建pod

root@192:/usr/local/src/k8s-Resource-N76/case11-secret# cat 3-secret-Opaque-mount.yaml 
#apiVersion: extensions/v1beta1
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myserver-myapp-app1-deployment
  namespace: myserver
spec:
  replicas: 1
  selector:
    matchLabels:
      app: myserver-myapp-app1
  template:
    metadata:
      labels:
        app: myserver-myapp-app1
    spec:
      containers:
      - name: myserver-myapp-app1
        image: tomcat:7.0.94-alpine
        ports:
        - containerPort: 8080
        volumeMounts:
        - mountPath: /data/myserver/auth #secert卷挂载的位置
          name: myserver-auth-secret 
      volumes:
      - name: myserver-auth-secret
        secret:
          secretName: mysecret-data #挂载指定的secret,挂载后会将base64解密为明文

---
apiVersion: v1
kind: Service
metadata:
  name: myserver-myapp-app1
  namespace: myserver
spec:
  ports:
  - name: http
    port: 8080
    targetPort: 8080
    nodePort: 30018
    protocol: TCP
  type: NodePort
  selector:
    app: myserver-myapp-app1

进入pod 进入挂载secret卷的目录,发现用户名密码已经明文保存
image

secert卷用户名密码是保存在宿主机的(类似emptydir)

image

image

使用sercet卷kubernetes.io/tls为nginx提供证书

对nginx使用secret卷传递nginx自建证书,以建立https访问。

apiVersion: v1
kind: ConfigMap #使用configmap提供nginx配置
metadata:
  name: nginx-config
  namespace: myserver
data:
 default: |
    server {
       listen       80;
       server_name  www.mysite.com;
       listen 443 ssl;
       ssl_certificate /etc/nginx/conf.d/certs/tls.crt;   #添加证书
       ssl_certificate_key /etc/nginx/conf.d/certs/tls.key;

       location / {
           root /usr/share/nginx/html; 
           index index.html;
           if ($scheme = http ){  #未加条件判断,会导致死循环
              rewrite / https://www.mysite.com permanent; #将http跳转我https协议
           }  

           if (!-e $request_filename) {
               rewrite ^/(.*) /index.html last;
           }
       }
    }

---
#apiVersion: extensions/v1beta1
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myserver-myapp-frontend-deployment
  namespace: myserver
spec:
  replicas: 1
  selector:
    matchLabels:
      app: myserver-myapp-frontend
  template:
    metadata:
      labels:
        app: myserver-myapp-frontend
    spec:
      containers:
      - name: myserver-myapp-frontend
        image: nginx:1.20.2-alpine 
        ports:
          - containerPort: 80
        volumeMounts:
          - name: nginx-config
            mountPath:  /etc/nginx/conf.d/myserver
          - name: myserver-tls-key
            mountPath:  /etc/nginx/conf.d/certs
      volumes:
      - name: nginx-config
        configMap:
          name: nginx-config
          items:
             - key: default
               path: mysite.conf
      - name: myserver-tls-key
        secret:
          secretName: myserver-tls-key 


---
apiVersion: v1
kind: Service
metadata:
  name: myserver-myapp-frontend
  namespace: myserver
spec:
  type: NodePort
  ports:
  - name: http
    port: 80
    targetPort: 80
    nodePort: 30018
    protocol: TCP
  - name: htts
    port: 443
    targetPort: 443
    nodePort: 30019
    protocol: TCP
  selector:
    app: myserver-myapp-frontend 

在生成pod之前,我们需要创建证书公钥和私钥

 openssl req -x509 -sha256 -newkey rsa:4096 -keyout ca.key -out ca.crt -days 3560 -nodes -subj '/CN=www.ca.com'
 openssl req -new -newkey rsa:4096 -keyout server.key -out server.csr -nodes -subj '/CN=www.mysite.com'
 openssl x509 -req -sha256 -days 3650 -in server.csr -CA ca.crt -CAkey ca.key -set_serial 01 -out server.crt
 kubectl create secret tls myserver-tls-key --cert=./server.crt --key=./server.key -n myserver

image

之后生成pod
image

进入pod 找到挂载的nginx配置 以及证书公钥和私钥
image

image

修改在nginx配置文件引用mysite.conf 重启nginx
image

可以看到443端口已经开启
![image](/i/l/?n=23&i=blog/3185455/202305/3185455-
20230519164843918-599997395.png)

查看svc 修改haproxy

image

image

修改宿主机hosts文件(域名已更改)测试https登陆成功

image

使用secret提供镜像信息认证 (略)

apiVersion: apps/v1
kind: Deployment
metadata:
  name: myserver-myapp-frontend-deployment
  namespace: myserver
spec:
  replicas: 1
  selector:
    matchLabels:
      app: myserver-myapp-frontend
  template:
    metadata:
      labels:
        app: myserver-myapp-frontend
    spec:
      containers:
      - name: myserver-myapp-frontend
        image: registry.cn-qingdao.aliyuncs.com/zhangshijie/nginx:1.16.1-alpine-perl
        ports:
          - containerPort: 80
      imagePullSecrets:
        - name: aliyun-registry-image-pull-key

---
apiVersion: v1
kind: Service
metadata:
  name: myserver-myapp-frontend
  namespace: myserver
spec:
  ports:
  - name: http
    port: 80
    targetPort: 80
    nodePort: 30018
    protocol: TCP
  type: NodePort
  selector:
    app: myserver-myapp-frontend

Statefulset

StatefulSet 是用来管理有状态应用的工作负载 API 对象。用来管理某 Pod 集合的部署和扩缩, 并为这些 Pod 提供持久存储和持久标识符。

Statefulset 作用

  • Statefulset为了解决有状态服务的集群部署、集群之间的数据同步问题(MySQL主从、Redis Cluster、ES集群等)
  • Statefulset所管理的Pod拥有唯一且固定的Pod名称
  • Statefulset按照顺序对pod进行启停、伸缩和回收
  • Headless Services(无头服务,请求的解析直接解析到pod IP) 例如mysql的pod直接指定ip,可以区分主从,读请求都访问从库pod的ip

image

statefulset的yaml

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: myserver-myapp
  namespace: myserver
spec:
  replicas: 3
  serviceName: "myserver-myapp-service"
  selector:
    matchLabels:
      app: myserver-myapp-frontend
  template:
    metadata:
      labels:
        app: myserver-myapp-frontend
    spec:
      containers:
      - name: myserver-myapp-frontend
        image: nginx:1.20.2-alpine
        ports:
          - containerPort: 80

---
apiVersion: v1
kind: Service
metadata:
  name: myserver-myapp-service
  namespace: myserver
spec:
  clusterIP: None
  ports:
  - name: http
    port: 80
  selector:
    app: myserver-myapp-frontend

可以看出 pod的名字是固定的,从0开始;而且pod也是依次创建的。如果删除pod,也是从后向前依次删除
image

image

另外,statefulset使用的svc是headless。其特点是没有clusterip 可以直接ping svc的域名,会以接近轮询的方式直接访问后端pod的ip
image

image

headless Service使用场景

  1. 自主选择权,有时候client想自己决定使用哪个Real Server,可以通过查询DNS来获取Real Server的信息
  2. headless service关联的每个endpoint(也就是Pod),都会有对应的DNS域名;这样Pod之间就可以互相访问

为什么要用headless service+statefulSet部署有状态应用

1.headless service会为关联的service分配一个域
<service name>.$<namespace name>.svc.cluster.local
2.StatefulSet会为关联的Pod保持一个不变的Pod Name
statefulset中Pod的hostname格式为$(StatefulSet name)-$(pod序号)
3.StatefulSet会为关联的Pod分配一个dnsName
$<Pod Name>.$<service name>.$<namespace name>.svc.cluster.local

DaemonSet简介:

DaemonSet 在当前集群中每个节点运行同一个pod,当有新的节点加入集群时也会为新的节点配置相同的pod,当节点从集群中移除时其pod也会被kubernetes回收,删除DaemonSet 控制器将删除其创建的所有的pod。

image

DaemonSet 的一些典型用法:

  • 在每个节点上运行集群守护进程
  • 在每个节点上运行日志收集守护进程
  • 在每个节点上运行监控守护进程

1 nginx容器的daemonset yaml文件

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: myserver-myapp
  namespace: myserver
spec:
  selector:
    matchLabels:
      app: myserver-myapp-frontend
  template:
    metadata:
      labels:
        app: myserver-myapp-frontend
    spec:
      tolerations:
      # this toleration is to have the daemonset runnable on master nodes
      # remove it if your masters can't run pods
      - key: node-role.kubernetes.io/master ##添加容忍,让pod也可以在master上
        operator: Exists
        effect: NoSchedule
      hostNetwork: true        #使用宿主机网路
      hostPID: true
      containers:
      - name: myserver-myapp-frontend
        image: nginx:1.20.2-alpine
        ports:
          - containerPort: 80

---
apiVersion: v1
kind: Service
metadata:
  name: myserver-myapp-frontend
  namespace: myserver
spec:
  ports:
  - name: http
    port: 80
    targetPort: 80
    nodePort: 30018
    protocol: TCP
  type: NodePort
  selector:
    app: myserver-myapp-frontend

文件中并没有设定部署几个pod,而k8s自动在每个node节点上生成了1个pod。
image

因为是宿主机网络,endpoint是宿主机地址
image

2 系统日志收集fluentd-elasticsearch的yaml

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: fluentd-elasticsearch
  namespace: kube-system
  labels:
    k8s-app: fluentd-logging
spec:
  selector:
    matchLabels:
      name: fluentd-elasticsearch
  template:
    metadata:
      labels:
        name: fluentd-elasticsearch
    spec:
      tolerations:
      # this toleration is to have the daemonset runnable on master nodes
      # remove it if your masters can't run pods
      - key: node-role.kubernetes.io/master
        operator: Exists
        effect: NoSchedule
      containers:
      - name: fluentd-elasticsearch
        image: quay.io/fluentd_elasticsearch/fluentd:v2.5.2
        resources:
          limits:
            memory: 200Mi
          requests:
            cpu: 100m
            memory: 200Mi
        volumeMounts:
        - name: varlog
          mountPath: /var/log
        - name: varlibdockercontainers
          mountPath: /var/lib/docker/containers
          readOnly: true
      terminationGracePeriodSeconds: 30
      volumes:
      - name: varlog
        hostPath:
          path: /var/log
      - name: varlibdockercontainers
        hostPath:
          path: /var/lib/docker/containers

image

部署Promethus的yaml##

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: node-exporter
  namespace: myserver
  labels:
    k8s-app: node-exporter
spec:
  selector:
    matchLabels:
        k8s-app: node-exporter
  template:
    metadata:
      labels:
        k8s-app: node-exporter
    spec:
      tolerations:
        - effect: NoSchedule
          key: node-role.kubernetes.io/master
      containers:
      - image: prom/node-exporter:v1.3.1
        imagePullPolicy: IfNotPresent
        name: prometheus-node-exporter
        ports:
        - containerPort: 9100
          hostPort: 9100
          protocol: TCP
          name: metrics
        volumeMounts:
        - mountPath: /host/proc
          name: proc
        - mountPath: /host/sys
          name: sys
        - mountPath: /host
          name: rootfs
        args:
        - --path.procfs=/host/proc
        - --path.sysfs=/host/sys
        - --path.rootfs=/host
      volumes:
        - name: proc
          hostPath:
            path: /proc
        - name: sys
          hostPath:
            path: /sys
        - name: rootfs
          hostPath:
            path: /
      hostNetwork: true
      hostPID: true
---
apiVersion: v1
kind: Service   
metadata:
  annotations:
    prometheus.io/scrape: "true"
  labels:
    k8s-app: node-exporter
  name: node-exporter
  namespace: myserver
spec:
  type: NodePort
  ports:
  - name: http
    port: 9100
    nodePort: 32100
    protocol: TCP
  selector:
    k8s-app: node-exporter

image

可以登录宿主机的9100端口直接看到 收集到的日志信息

image

image

pause容器

Pause 容器,又叫 Infra 容器,是pod的基础容器,镜像体积只有几百KB左右,配置在kubelet中,主要的功能是一个pod中多个容器的网络通信。
Infra 容器被创建后会初始化 Network Namespace,之后其它容器就可以加入到 Infra 容器中共享Infra 容器的网络了,因此如果一个 Pod 中的两个容器 A 和 B,那么关系如下:

  • A容器和B容器能够直接使用 localhost 通信;
  • A容器和B容器可以可以看到网卡、IP与端口监听信息。
  • Pod 只有一个 IP 地址,也就是该 Pod 的 Network Namespace 对应的IP 地址(由Infra 容器初始化并创建)。
  • k8s环境中的每个Pod有一个独立的IP地址(前提是地址足够用),并且此IP被当前 Pod 中所有容器在内部共享使用。
  • pod删除后Infra 容器随机被删除,其IP被回收。

Pause容器共享的Namespace:

  1. NET Namespace:Pod中的多个容器共享同一个网络命名空间,即使用相同的IP和端口信息。
  2. IPC Namespace:Pod中的多个容器可以使用System V IPC或POSIX消息队列进行通信。
  3. UTS Namespace:pod中的多个容器共享一个主机名。MNT Namespace、PID Namespace、User Namespace未共享。

image

验证 先创建一个pod
image

进入pod后查看网卡id
image

在宿主机上找到这个id的网卡
image

image

可以从宿主机找到是哪个网卡的namespace
nsenter --net=/run/netns/cni-a62dcf81-e2da-b70c-2794-5c8195d31c5e ifconfig
image

同一个pod的不同容器文件系统不同,pid也不同。但是网络地址,网卡是相同的。

init容器

Init 容器是一种特殊容器,在 Pod 内的应用容器启动之前运行。Init 容器可以包括一些应用镜像中不存在的实用工具和安装脚本。可以在 Pod 的规约中与用来描述应用容器的 containers 数组平行的位置指定 Init 容器

init容器的作用:
1.可以为业务容器提前准备好业务容器的运行环境,比如将业务容器需要的配置文件提前生成并放在指定位置、检查数据权限或完整性、软件版本等基础运行环境。。
2.可以在运行业务容器之前准备好需要的业务数据,比如从OSS下载、或者从其它位置copy。
3.检查依赖的服务是否能够访问。

init容器的特点:
1.一个pod可以有多个业务容器还能在有多个init容器,但是每个init容器和业务容器的运行环境都是隔离的。
2.init容器会比业务容器先启动。
3.init容器运行成功之后才会继续运行业务容器。
4.如果一个pod有多个init容器,则需要从上到下逐个运行并且全部成功,最后才会运行业务容器。
5.init容器不支持探针检测(因为初始化完成后就退出再也不运行了)。

init容器的yaml文件

kind: Deployment
#apiVersion: extensions/v1beta1
apiVersion: apps/v1
metadata:
  labels:
    app: myserver-myapp 
  name: myserver-myapp-deployment-name
  namespace: myserver
spec:
  replicas: 1 
  selector:
    matchLabels:
      app: myserver-myapp-frontend
  template:
    metadata:
      labels:
        app: myserver-myapp-frontend
    spec:
      containers:
        - name: myserver-myapp-container
          image: nginx:1.20.0 
          #imagePullPolicy: Always
          volumeMounts:
          - mountPath: "/usr/share/nginx/html/myserver"
            name: myserver-data
          - name: tz-config
            mountPath: /etc/localtime
      initContainers:   #先执行init容器,再执行其他容器
        - name: init-web-data
          image: centos:7.9.2009
          command: ['/bin/bash','-c',"for i in `seq 1 10`;do echo '<h1>'$i web page at $(date +%Y%m%d%H%M%S) '<h1>' >> /data/nginx/html/myserver/index.html;sleep 1;done"]
          volumeMounts:
          - mountPath: "/data/nginx/html/myserver"
            name: myserver-data
          - name: tz-config
            mountPath: /etc/localtime
        - name: change-data-owner
          image: busybox:1.28
          command: ['/bin/sh','-c',"/bin/chmod 644 /data/nginx/html/myserver/* -R"]
          volumeMounts:
          - mountPath: "/data/nginx/html/myserver"
            name: myserver-data
          - name: tz-config
            mountPath: /etc/localtime
      volumes:
      - name: myserver-data
        hostPath:
          path: /tmp/data/html
      - name: tz-config
        hostPath:
          path: /etc/localtime 

---
kind: Service
apiVersion: v1
metadata:
  labels:
    app: myserver-myapp-service
  name: myserver-myapp-service-name
  namespace: myserver
spec:
  type: NodePort
  ports:
  - name: http
    port: 80
    targetPort: 80
    nodePort: 30080
  selector:
    app: myserver-myapp-frontend

image

image

pod生命周期

Pod 遵循预定义的生命周期,起始于 Pending 阶段, 如果至少其中有一个主要容器正常启动,则进入 Running,之后取决于 Pod 中是否有容器以失败状态结束而进入 Succeeded 或者 Failed 阶段。
在 Pod 运行期间,kubelet 能够重启容器以处理一些失效场景。 在 Pod 内部,Kubernetes 跟踪不同容器的状态并确定使 Pod 重新变得健康所需要采取的动作。
Pod 在其生命周期中只会被调度一次。 一旦 Pod 被调度(分派)到某个节点,Pod 会一直在该节点运行,直到 Pod 停止或者被终止。

和一个个独立的应用容器一样,Pod 也被认为是相对临时性(而不是长期存在)的实体。 Pod 会被创建、赋予一个唯一的 ID(UID), 并被调度到节点,并在终止(根据重启策略)或删除之前一直运行在该节点。
如果一个节点死掉了,调度到该节点的 Pod 也被计划在给定超时期限结束后删除。
Pod 自身不具有自愈能力。如果 Pod 被调度到某节点而该节点之后失效, Pod 会被删除;类似地,Pod 无法在因节点资源耗尽或者节点维护而被驱逐期间继续存活。 Kubernetes 使用一种高级抽象来管理这些相对而言可随时丢弃的 Pod 实例, 称作控制器。
任何给定的 Pod (由 UID 定义)从不会被“重新调度(rescheduled)”到不同的节点; 相反,这一 Pod 可以被一个新的、几乎完全相同的 Pod 替换掉。 如果需要,新 Pod 的名字可以不变,但是其 UID 会不同。
如果某物声称其生命期与某 Pod 相同,例如存储卷, 这就意味着该对象在此 Pod (UID 亦相同)存在期间也一直存在。 如果 Pod 因为任何原因被删除,甚至某完全相同的替代 Pod 被创建时, 这个相关的对象(例如这里的卷)也会被删除并重建。

探针

探针是由 kubelet 对容器执行的定期诊断,以保证Pod的状态始终处于运行状态,要执行诊断,kubelet 调用由容器实现的Handler(处理程序),也成为Hook(钩子),有三种类型的处理程序:

  • ExecAction #在容器内执行指定命令,如果命令退出时返回码为0则认为诊断成功。
  • TCPSocketAction #对指定端口上的容器的IP地址进行TCP检查,如果端口打开,则诊断被认为是成功的。
  • HTTPGetAction:#对指定的端口和路径上的容器的IP地址执行HTTPGet请求,如果响应的状态码大于等于200且小于 400,则诊断被认为是成功的。(生产中较多使用)

每次探测都将获得以下三种结果之一:

  • 成功:容器通过了诊断。
  • 失败:容器未通过诊断。
  • 未知:诊断失败,因此不会采取任何行动。

容器重启策略

Pod 的 spec 中包含一个 restartPolicy 字段,其可能取值包括 Always、OnFailure 和 Never。默认值是 Always。

restartPolicy 适用于 Pod 中的所有容器。restartPolicy 仅针对同一节点上 kubelet 的容器重启动作。当 Pod 中的容器退出时,kubelet 会按指数回退方式计算重启的延迟(10s、20s、40s、...),其最长延迟为 5 分钟。 一旦某容器执行了 10 分钟并且没有出现问题,kubelet 对该容器的重启回退计时器执行重置操作。

restartPolicy:

  • Always:当容器异常时,k8s自动重启该容器,ReplicationController/Replicaset/Deployment,默认为Always。
  • OnFailure:当容器失败时(容器停止运行且退出码不为0),k8s自动重启该容器。
  • Never:不论容器运行状态如何都不会重启该容器,Job或CronJob

imagePullPolicy (镜像拉取策略)::

  • IfNotPresent:node节点没有此镜像就去指定的镜像仓库拉取,node有就使用node本地镜像。
  • Always:每次重建pod都会重新拉取镜像
  • Never:从不到镜像中心拉取镜像,只使用本地镜像

探针类型

startupProbe: #启动探针,kubernetes v1.16引入
判断容器内的应用程序是否已启动完成,如果配置了启动探测,则会先禁用所有其它的探测,直到startupProbe检测成功为止,如果startupProbe探测失败,则kubelet将杀死容器,容器将按照重启策略进行下一步操作,如果容器没有提供启动探测,则默认状态为成功
livenessProbe: #存活探针
检测容器容器是否正在运行,如果存活探测失败,则kubelet会杀死容器,并且容器将受到其重启策略的影响,如果容器不提供存活探针,则默认状态为 Success,livenessProbe用于控制是否重启pod。
readinessProbe: #就绪探针
如果就绪探测失败,端点控制器将从与Pod匹配的所有Service的端点中删除该Pod的IP地址,初始延迟之前的就绪状态默认为Failure(失败),如果容器不提供就绪探针,则默认状态为 Success,readinessProbe用于控制pod是否添加至service。

探针配置参数:

initialDelaySeconds: 120
初始化延迟时间,告诉kubelet在执行第一次探测前应该等待多少秒,默认是0秒,最小值是0
periodSeconds: 60
探测周期间隔时间,指定了kubelet应该每多少秒秒执行一次存活探测,默认是 10 秒。最小值是 1
timeoutSeconds: 5
单次探测超时时间,探测的超时后等待多少秒,默认值是1秒,最小值是1。
successThreshold: 1
从失败转为成功的重试次数,探测器在失败后,被视为成功的最小连续成功数,默认值是1,存活探测的这个值必须是1,最小值是 1。
failureThreshold: 3
从成功转为失败的重试次数,当Pod启动了并且探测到失败,Kubernetes的重试次数,存活探测情况下的放弃就意味着重新启动容器,就绪探
测情况下的放弃Pod 会被打上未就绪的标签,默认值是3,最小值是1。

HTTPGetAction的yaml文件

apiVersion: apps/v1
kind: Deployment
metadata:
  name: myserver-myapp-frontend-deployment
  namespace: myserver
spec:
  replicas: 1
  selector:
    matchLabels: #rs or deployment
      app: myserver-myapp-frontend-label
    #matchExpressions:
    #  - {key: app, operator: In, values: [myserver-myapp-frontend,ng-rs-81]}
  template:
    metadata:
      labels:
        app: myserver-myapp-frontend-label
    spec:
      containers:
      - name: myserver-myapp-frontend-label
        image: nginx:1.20.2
        ports:
        - containerPort: 80
        readinessProbe: ##添加就绪探针
        livenessProbe:  ##添加存活探针
          httpGet:
            #path: /monitor/monitor.html
            path: /index.html
            port: 80
          initialDelaySeconds: 5
          periodSeconds: 3
          timeoutSeconds: 1
          successThreshold: 1
          failureThreshold: 3


---
apiVersion: v1
kind: Service
metadata:
  name: myserver-myapp-frontend-service
  namespace: myserver
spec:
  ports:
  - name: http
    port: 81
    targetPort: 80
    nodePort: 40012
    protocol: TCP
  type: NodePort
  selector:
    app: myserver-myapp-frontend-label

这是正常状态
image

将端口改变后查看效果
image

image
由于端口找不到,存活探针规制使pod重启3次后报错;就绪探针使pod无法在svc上挂载

TCPGetAction的yaml文件

apiVersion: apps/v1
kind: Deployment
metadata:
  name: myserver-myapp-frontend-deployment
  namespace: myserver
spec:
  replicas: 1
  selector:
    matchLabels: #rs or deployment
      app: myserver-myapp-frontend-label
    #matchExpressions:
    #  - {key: app, operator: In, values: [myserver-myapp-frontend,ng-rs-81]}
  template:
    metadata:
      labels:
        app: myserver-myapp-frontend-label
    spec:
      containers:
      - name: myserver-myapp-frontend-label
        image: nginx:1.20.2
        ports:
        - containerPort: 80
        livenessProbe:
        #readinessProbe:
          tcpSocket:
            port: 80
            #port: 8080
          initialDelaySeconds: 5
          periodSeconds: 3
          timeoutSeconds: 5
          successThreshold: 1
          failureThreshold: 3


---
apiVersion: v1
kind: Service
metadata:
  name: myserver-myapp-frontend-service
  namespace: myserver
spec:
  ports:
  - name: http
    port: 81
    targetPort: 80
    nodePort: 40012
    protocol: TCP
  type: NodePort
  selector:
    app: myserver-myapp-frontend-label

可以看到结果类似
image

ExecAction方式探针容器的yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: myserver-myapp-redis-deployment
  namespace: myserver
spec:
  replicas: 1
  selector:
    matchLabels: #rs or deployment
      app: myserver-myapp-redis-label
    #matchExpressions:
    #  - {key: app, operator: In, values: [myserver-myapp-redis,ng-rs-81]}
  template:
    metadata:
      labels:
        app: myserver-myapp-redis-label
    spec:
      containers:
      - name: myserver-myapp-redis-container
        image: redis
        ports:
        - containerPort: 6379
        livenessProbe:
        #readinessProbe:
          exec:
            command:
            #- /apps/redis/bin/redis-cli
            - /usr/local/bin/redis-cli
            - quit
          initialDelaySeconds: 5
          periodSeconds: 3
          timeoutSeconds: 5
          successThreshold: 1
          failureThreshold: 3

---
apiVersion: v1
kind: Service
metadata:
  name: myserver-myapp-redis-service
  namespace: myserver
spec:
  ports:
  - name: http
    port: 6379
    targetPort: 6379
    nodePort: 40016
    protocol: TCP
  type: NodePort
  selector:
    app: myserver-myapp-redis-label

由于目录位置不对,容器直接未启动,无法进行到探针步骤~~~~
image

startupProbe.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: myserver-myapp-frontend-deployment
  namespace: myserver
spec:
  replicas: 1
  selector:
    matchLabels: #rs or deployment
      app: myserver-myapp-frontend-label
    #matchExpressions:
    #  - {key: app, operator: In, values: [myserver-myapp-frontend,ng-rs-81]}
  template:
    metadata:
      labels:
        app: myserver-myapp-frontend-label
    spec:
      containers:
      - name: myserver-myapp-frontend-label
        image: nginx:1.20.2
        ports:
        - containerPort: 80
        startupProbe:
          httpGet:
            path: /index.html
            port: 80
          initialDelaySeconds: 5 #首次检测延迟5s
          failureThreshold: 3  #从成功转为失败的次数
          periodSeconds: 3 #探测间隔周期


---
apiVersion: v1
kind: Service
metadata:
  name: myserver-myapp-frontend-service
  namespace: myserver
spec:
  ports:
  - name: http
    port: 81
    targetPort: 80
    nodePort: 40012
    protocol: TCP
  type: NodePort
  selector:
    app: myserver-myapp-frontend-label

探测结果
image

startupProbe-livenessProbe-readinessProbe.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: myserver-myapp-frontend-deployment
  namespace: myserver
spec:
  replicas: 3
  selector:
    matchLabels: #rs or deployment
      app: myserver-myapp-frontend-label
    #matchExpressions:
    #  - {key: app, operator: In, values: [myserver-myapp-frontend,ng-rs-81]}
  template:
    metadata:
      labels:
        app: myserver-myapp-frontend-label
    spec:
      terminationGracePeriodSeconds: 60
      containers:
      - name: myserver-myapp-frontend-label
        image: nginx:1.20.2
        ports:
        - containerPort: 80
        startupProbe:
          httpGet:
            path: /index.html
            port: 80
          initialDelaySeconds: 5 #首次检测延迟5s
          failureThreshold: 3  #从成功转为失败的次数
          periodSeconds: 3 #探测间隔周期
        readinessProbe:
          httpGet:
            #path: /monitor/monitor.html
            path: /index.html
            port: 80
          initialDelaySeconds: 5
          periodSeconds: 3
          timeoutSeconds: 5
          successThreshold: 1
          failureThreshold: 3
        livenessProbe:
          httpGet:
            #path: /monitor/monitor.html
            path: /index.html
            port: 80
          initialDelaySeconds: 5
          periodSeconds: 3
          timeoutSeconds: 5
          successThreshold: 1
          failureThreshold: 3


---
apiVersion: v1
kind: Service
metadata:
  name: myserver-myapp-frontend-service
  namespace: myserver
spec:
  ports:
  - name: http
    port: 81
    targetPort: 80
    nodePort: 40012
    protocol: TCP
  type: NodePort
  selector:
    app: myserver-myapp-frontend-label

要注意启动探针最先检测,成功之后再进行探针其他检测。如果失败就直接杀死容器。
先修改启动探针端口为88
image

存活探针端口为88
image

就绪探针端口为88
image

postStart and preStop handlers

postStart 和 preStop handlers 处理函数:

postStart-Pod启动后立即执行指定的查操作:

  • Pod被创建后立即执行,即不等待pod中的服务启动。
  • 如果postStart执行失败pod不会继续创建

preStop:

  • 在pod被停止之前执行
  • 如果preStop一直执行不完成,则最后宽限2秒后强制删除

image

示例:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: myserver-myapp1-lifecycle
  labels:
    app: myserver-myapp1-lifecycle
  namespace: myserver
spec:
  replicas: 1
  selector:
    matchLabels:
      app: myserver-myapp1-lifecycle-label
  template:
    metadata:
      labels:
        app: myserver-myapp1-lifecycle-label
    spec:
      terminationGracePeriodSeconds: 60
      containers:
      - name: myserver-myapp1-lifecycle-label
        image: tomcat:7.0.94-alpine
        lifecycle:
          postStart:
            exec:
             #command: 把自己注册到注册在中心
              command: ["/bin/sh", "-c", "echo 'Hello from the postStart handler' >> /usr/local/tomcat/webapps/ROOT/index.html"]

            #httpGet:
            #  #path: /monitor/monitor.html
            #  host: www.magedu.com
            #  port: 80
            #  scheme: HTTP
            #  path: index.html
          preStop:
            exec:
             #command: 把自己从注册中心移除
              command:
                - /bin/bash
                - -c
                - 'sleep 10000000'
              #command: ["/usr/local/tomcat/bin/catalina.sh","stop"]
              #command: ['/bin/sh','-c','/path/preStop.sh']
        ports:
          - name: http
            containerPort: 8080

---
apiVersion: v1
kind: Service
metadata:
  name: myserver-myapp1-lifecycle-service
  namespace: myserver
spec:
  ports:
  - name: http
    port: 80
    targetPort: 8080
    nodePort: 30012
    protocol: TCP
  type: NodePort
  selector:
    app: myserver-myapp1-lifecycle-label

注意 podstart在startprobe探针之后执行。

Pod的终止流程:

1.创建pod

  1. 向API-Server提交创建请求、API-Server完成鉴权和准入并将事件写入etcd
  2. kube-scheduler完成调度流程
  3. kubelet创建并启动pod、然后执行postStart
  4. 周期进行livenessProbe
  5. 进入running状态
  6. readinessProbe检测通过后,service关联pod
  7. 接受客户端请求

2.删除pod

  1. 向API-Server提交删除请求、API-Server完成鉴权和准入并将事件写入etcd
  2. Pod被设置为”Terminating”状态、从service的Endpoints列表中删除并不再接受客户端请求。
  3. pod执行PreStop
  4. kubelet向pod中的容器发送SIGTERM信号(正常终止信号)终止pod里面的主进程,这个信号让容器知道自己很快将会被关闭
  5. terminationGracePeriodSeconds: 60 #可选终止等待期(pod删除宽限期),如果有设置删除宽限时间,则等待宽限时间到期,否则最多等待30s,Kubernetes等
  6. 待指定的时间称为优雅终止宽限期,默认情况下是30秒,值得注意的是等待期与preStop Hook和SIGTERM信号并行执行,即Kubernetes可能不会等待preStop Hook
  7. 完成(最长30秒之后主进程还没有结束就就强制终止pod)。
  8. SIGKILL信号被发送到Pod,并删除Pod

基于nerdctl + buildkitd+containerd构建容器镜像

buildkitd组成部分:

buildkitd(服务端),⽬前⽀持runc和containerd作为镜像构建环境,默认是runc,可以更换为containerd。
buildctl(客户端),负责解析Dockerfile⽂件,并向服务端buildkitd发出构建请求。

⼀ 部署buildkitd:

wget https://github.com/moby/buildkit/releases/download/v0.11.6/buildkit-v0.11.6.linux-amd64.tar.gz
tar xvf buildkit-v0.11.6.linux-amd64.tar.gz
mv bin/* /usr/local/bin/

vim /lib/systemd/system/buildkit.socket

[Unit]
Description=BuildKit
Documentation=https://github.com/moby/buildkit
[Socket]
ListenStream=%t/buildkit/buildkitd.sock
[Install]
WantedBy=sockets.target

vim /lib/systemd/system/buildkitd.service

[Unit]
Description=BuildKit
Requires=buildkit.socket
After=buildkit.socketDocumentation=https://github.com/moby/buildkit
[Service]
ExecStart=/usr/local/bin/buildkitd --oci-worker=false --containerd-worker=true
[Install]
WantedBy=multi-user.target

systemctl daemon-reload
systemctl enable buildkitd
systemctl restart buildkitd
systemctl status buildkitd

image

⼆ 测试镜像构建:

~# vim /etc/profile
source <(nerdctl completion bash)
~# source /etc/profile

测试结果 nerdctl 命令参数可用tab补全
image

harbor证书分发:之前已签发过 验证结果

image

image

使用buildkit构建镜像
image

root@192:/usr/local/src/20230507/ubuntu# cat Dockerfile 
FROM ubuntu:22.04
MAINTAINER "jack [email protected]"


#ADD sources.list /etc/apt/sources.list

RUN apt update && apt  install -y iproute2  ntpdate  tcpdump telnet traceroute nfs-kernel-server nfs-common  lrzsz tree  openssl libssl-dev libpcre3 libpcre3-dev zlib1g-dev ntpdate tcpdump telnet traceroute  gcc openssh-server lrzsz tree  openssl libssl-dev libpcre3 libpcre3-dev zlib1g-dev ntpdate tcpdump telnet traceroute iotop unzip zip make


ADD nginx-1.22.0.tar.gz /usr/local/src/
RUN cd /usr/local/src/nginx-1.22.0 && ./configure --prefix=/apps/nginx && make && make install  && ln -sv /apps/nginx/sbin/nginx /usr/bin
RUN groupadd  -g 2088 nginx && useradd  -g nginx -s /usr/sbin/nologin -u 2088 nginx && chown -R nginx.nginx /apps/nginx
ADD nginx.conf /apps/nginx/conf/
ADD frontend.tar.gz /apps/nginx/html/
RUN chown -R nginx.nginx /apps/nginx

EXPOSE 80 443
#ENTRYPOINT ["nginx"]
CMD ["nginx","-g","daemon off;"]
root@192:/usr/local/src/20230507/ubuntu# cat build-command.sh 
#!/bin/bash
#docker build -t harbor.magedu.net/myserver/nginx:v1 .
#docker push harbor.magedu.net/myserver/nginx:v1

/usr/bin/nerdctl build -t harbor.linuxarchitect.io/basic/nginx-base:1.22.0 .

/usr/bin/nerdctl push harbor.linuxarchitect.io/basic/nginx-base:1.22.0

root@192:/usr/local/src/20230507/ubuntu# cat sources.list 

deb http://mirrors.tuna.tsinghua.edu.cn/ubuntu/ jammy main restricted universe multiverse
# deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ jammy main restricted universe multiverse
deb http://mirrors.tuna.tsinghua.edu.cn/ubuntu/ jammy-updates main restricted universe multiverse
# deb-sr https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ jammy-updates main restricted universe multiverse
deb http://mirrors.tuna.tsinghua.edu.cn/ubuntu/ jammy-backports main restricted universe multiverse
# deb-sr https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ jammy-backports main restricted universe multiverse
deb http://mirrors.tuna.tsinghua.edu.cn/ubuntu/ jammy-security main restricted universe multiverse
# deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ jammy-security main restricted universe multiverse


# deb http://mirrors.tuna.tsinghua.edu.cn/ubuntu/ jammy-proposed main restricted universe multiverse
# deb-src http://mirrors.tuna.tsinghua.edu.cn/ubuntu/ jammy-proposed main restricted universe multiverse

执行build-command.sh

image

可看到成功创建镜像,拉取镜像并创建容器

image

标签:容器,name,kubernetes,--,nginx,详解,myapp,myserver,Pod
From: https://www.cnblogs.com/zhaoxiangyu-blog/p/17412439.html

相关文章

  • fpga 一月学习记录
    fpga一月学习记录4月初,导师突然接了一个fpga开发的项目,把我和另一个同学叫过来,让我们速成,学习了2个星期Verilog语法,了解了一下vivado的使用,虽然最终项目因故中止,但是一个月的fpga学习也值得记录一下。我的主要工作内容是实现一个数据接口转换,具体因为没有下板成功就不说了,主要是......
  • Python基础之字符编码和文件类型
    字符编码什么事字符编码?什么是字符编码?人类在与计算机交互时,用的都是人类能读懂的字符,如中文字符、英文字符、日文字符等,而计算机只能识别二进制。所以就产生了字符编码'''字符串类型、文本文件的内容都是由字符组成的,但凡涉及到字符的存取,都需要考虑字符编码的问题。字符编......
  • 周四
    题目描述:给定一个字符串s,你需要反转其中所有的元音字母。示例1:输入:"hello"输出:"holle"示例2:输入:"leetcode"输出:"leotcede"设计思路:首先,我们需要明确什么是元音字母,即a、e、i、o、u这五个字母。接下来,我们可以使用双指针的方法,一个指针从字符串头部开始,一个......
  • AI智慧安监EasyCVR平台使用时CPU占用与实际使用不符是什么原因?
    EasyCVR平台可支持多协议、多类型设备接入,平台可在复杂的网络环境中,将分散的各类视频资源进行统一汇聚、整合、集中管理,实现视频资源的鉴权管理、按需调阅、全网分发、智能分析等。平台采用可视化设计,可支持监测CPU使用、服务器内存、带宽、网络运行环境、设备状态等数据。有用......
  • Exchange EMS 迁移用户邮箱
    查看邮箱数据库里所有的用户邮箱Get-Mailbox-DatabaseDB01获取邮箱数据库系统邮箱:Get-Mailbox-arbitration-DatabaseDB01将邮箱数据库testDB上的用户邮箱迁移至邮箱数据库testDB2:Get-Mailbox-DatabasetestDB|New-MoveRequest-TargetDatabasetestDB2查看迁移请求完成......
  • 美食极速版
              Email:[email protected] ......
  • Spring事件常见错误
    案例1:试图处理并不会抛出的事件Spring事件的设计比较简单。说白了,就是监听器设计模式在Spring中的一种实现,参考下图: 从图中我们可以看出,Spring事件包含以下三大组件。(https://www.java567.com,搜"spring")事件(Event):用来区分和定义不同的事件,在Spring中,常见的如ApplicationEv......
  • prophet翻译(八)--- 异常值
    异常值异常值可以影响Prophet的预测结果,主要有两种方式。下面的示例中,我们使用之前提到的R页面的日志化维基百科访问量数据进行预测,但添加了一段错误的数据:#Pythondf=pd.read_csv('https://raw.githubusercontent.com/facebook/prophet/main/examples/example_wp_log_R_outl......
  • chrome插件脚本background_script和content_script
    Chrome在一次更新之后,出于安全考虑,完全的禁止了content_script从https向http发起ajax请求,即使正常情况下也会在console里给出提示。这对于Web来讲是好事,但对于扩展来讲就是坏事。平时可以很容易的请求数据,现在就没那么容易了。好在chrome还提供了background_scrip......
  • 遇到OOM之后应该怎么办?
    OOM产生的原因OOM可能产生的原因有以下几种:内存泄漏:内存泄漏是指程序中未被使用的对象仍然占用着内存空间,导致内存无法被垃圾回收机制回收。当程序中存在大量的内存泄漏时,就会导致内存不足。内存分配不当:如果程序中分配的内存过多或者在不需要的时候没有及时释放,就会导致......