K8S配置中的port、targetPort、nodePort和containerPort区别

  • port:port是k8s集群内部访问service的端口,即通过clusterIP:port可以访问到某个service
  • nodePort:nodePort是外部访问k8s集群中service的端口,通过nodeIP: nodePort可以从外部访问到某个service。
  • targetPort:targetPort是pod的端口,从port和nodePort来的流量经过kube-proxy流入到后端pod的targetPort上,最后进入容器。
  • containerPort:containerPort是pod内部容器的端口,targetPort映射到containerPort。

在这里插入图片描述

Statefulset

Statefulset为了解决有状态服务的部署(如某些服务启动是有依赖顺序)、集群之间的数据同步问题(如MySQL主从等)

  • Statefulset所管理的Pod用于唯一且固定的Pod名称(0,1,2,3)
  • Statefulset按照顺序对pod进行启停、伸缩和回收,回收从后向前,创建从前向后(前面的pod不会操作)。
  • Headless Services(无头服务,请求的解析区别于无状态服务直接解析到podip而不是service),将名称解析为地址

创建服务时会按照顺序先创建第一个(名称永远都是0),第一个创建完成前不会创建下一个。

实例

创建pod

---
#apiVersion: extensions/v1beta1
apiVersion: apps/v1
kind: StatefulSet #类型
metadata:
  name: myserver-myapp
  namespace: myserver
spec:
  replicas: 3
  serviceName: "myserver-myapp-service" #匹配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#没有service IP,直接通过pod名称解析地址
  ports:
  - name: http
    port: 80
  selector:
    app: myserver-myapp-frontend 

验证

 pod按照顺序创建,并且名称以0,1,2顺序命名

#跨namespace访问格式:pod名称-service名称-namespace名称-集群名称
ping  myserver-myapp-0.myserver-myapp-service.myserver.svc.k8s.local

请求先经过coredns进行域名解析然后轮询发给后面三个pod,不经过service.

MySQL读写分离,可以分为两个无头service,读去pod0,写去pod1,pod2.

DaemonSet

DaemonSet在当前集群中部分节点(部分不参与调度节点如master,SchedulingDisabled)运行同一个pod,当有新的节点加入集群时也会为新的节点配置相同的pod,当节集群中移除时其pod也会被kubernetes回收,删除DaemonSet控制器将删除其创建的所有的pod。

常用场景:calicoctl和日志收集

案例一

创建pod

---
#apiVersion: extensions/v1beta1
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 #污点,即使master节点被标记SchedulingDisabled也会创建pod
        operator: Exists
        effect: NoSchedule
      hostNetwork: true #减少service开销,使用宿主机网络,提高性能,service可以不使用
      hostPID: true #在容器中能查看到宿主机pid
      containers:
      - name: myserver-myapp-frontend
        image: nginx:1.20.2-alpine 
        ports:
          - containerPort: 80   #直接监听在宿主机的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

验证

 案例二-部署日志收集

部署prometheus

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: node-exporter
  namespace: monitoring 
  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

 

Pod状态和探针

Pod常见状态

  • Unschedulable: #Pod不能被调度, kube-scheduler没有匹配到合适的node节点
  • PodScheduled:#pod正处于调度中,在kube-scheduler刚开始调度的时候,还没有将pod分配到指定的node,在筛选出合适的节点后就会更新etcd数据,将pod分配到指定的node
  • Pending: #正在创建Pod但是Pod中的容器还没有全部被创建完成,处于此状态的Pod应该检查Pod依赖的存储是否有权限挂载等。
  • Failed:#Pod中有容器启动失败而导致pod工作异常。
  • Unknown:#由于某种原因无法获得pod的当前状态,通常是由于与pod所在的node节点通信错误"lnitialized:#所有pod中的初始化容器已经完成了
  • lmagePullBackOff:#!Pod所在的node节点下载镜像失败,镜像找到了但下不了,与InvalidlmageName区别
  • Running:#Pod内部的容器已经被创建并且启动,也包括探针检测通过了。
  • Ready:#表示pod中的容器已经可以提供访问服务
  • Error: #pod启动过程中发生错误NodeLost: #Pod所在节点失联
  • Waiting: #Pod 等待启动
  • Terminating: # Pod正在被销毁
  • CrashLoopBackOff: #kubelet正在重启pod
  • InvalidlmageName: #node节点无法解析镜像名称导致的镜像无法下载(404),找不到镜像
  • lmageInspectError:#无法校验镜像,镜像不完整导致
  • ErrlmageNeverPull:#策略禁止拉取镜像,镜像中心权限是私有等
  • RegistryUnavailable:#镜像服务器不可用,网络原因或harbor宕机
  • ErrlmagePull:#镜像拉取出错,超时或下载被强制终止
  • CreateContainerConfigError:#不能创建kubelet使用的容器配置
  • CreateContainerError:#创建容器失败
  • RunContainerError: #pod运行失败,容器中没有初始化PID为1的守护进程等ContainersNotInitialized:#pod没有初始化完毕
  • ContainersNotReady:#pod没有准备完毕
  • ContainerCreating:#pod正在创建中
  • PodInitializing:#pod正在初始化中
  • DockerDaemonNotReady: #node节点decker服务没有启动
  • NetworkPluginNotReady:#网络插件没有启动

Pause容器

Pause容器,又叫lnfra容器,是pod的基础容器,镜像体积只有几百KB左右,配置在kubelet(/etc/systemd/system/kubelet.service)中,主要的功能是一个pod中多个容器的网络通信。

lnfra容器被创建后会初始化Network Namespace,之后其它容器就可以加入到Infra容器中共享Infra 容器的网络了,因此如果一个Pod 中的两个容器A和B,那么关系如下:

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

Pause容器共享的Namespace:

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

Init容器

Init 容器是一种特殊容器,在Pod内的应用容器启动之前运行。Init 容器可以包括一些应用镜像中不存在的实用工具和安装脚本。

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

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

  • 它们总是运行到完成,只执行一次。
  • 每个都必须在下一个启动之前成功完成。

如果 Pod 的 Init 容器失败,kubelet 会不断地重启该 Init 容器直到该容器成功为止。 然而,如果 Pod 对应的 restartPolicy 值为 "Never",并且 Pod 的 Init 容器失败, 则 Kubernetes 会将整个 Pod 状态设置为失败。

init容器的作用:

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

init容器的特点:

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

案例

 创建pod

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.16.0
          #imagePullPolicy: Always
          volumeMounts:
          - mountPath: "/usr/share/nginx/html/myserver"    #挂载在/tmp/data/html
            name: myserver-data
      initContainers:
        - 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: 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
      volumes:
      - name: myserver-data
        hostPath:
          path: /tmp/data/html

---
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

验证

 

Helath Check

由发起者对容器进行周期性健康状态检测。周期检测相当于人类的周期性体检

案例一docker-compose检测

version: '3.6'
services:
  nginx-service:
    image: nginx:1.20.2
    container_name: nginx-web1
    expose:
      - 80
      - 443
    ports:
      - "8080:80"
    restart: always
    healthcheck: #添加服务健康状态检查
      test: ["CMD", "curl", "-f", "http://localhost"]
      interval: 5s #健康状态检查的间隔时间,默认为30s
      timeout: 5s #单次检查的失败超时时间,默认为30s
      retries: 3 #连续失败次数默认3次,当连续失败retries次数后将容器置为unhealthy状态
      start_period: 60s #60s后每间隔interval的时间检查一次,连续retries次后才将容器置为unhealthy状态, 但是start_period时间内检查成功就认为是检查成功并>装容器置于healthy状态

 案例二 命令添加

FROM nginx:1.20.2

maintainer "834943551@qq.com"


HEALTHCHECK --interval=5s --timeout=2s --retries=3 \
  CMD curl --silent --fail localhost:80 || exit 1

 

 

K8S的生命周期和探针

pod的生命周期,从start后可以配置postStart检测,运行过程中可以配置livenessProbe(存活探针)和readinessProbe(就绪探针),运行过程中Main Container提供主要业务服务,最后在stop前可以配置preStop操作。其中init、start和stop是一次性的,存活和就绪是周期性的。

探针简介

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

1) ExecAction:
在容器中执行指定命令,如命令退出时返回码为0则认为诊断成功
2) TCPSockerAction
对指定端口上的容器的IP地址进行TCP检查,如果端口打开则认为成功
3) HTTPGetAction
对指定端口和路径上的容器执行httpget请求,如果响应的状态码大约等于200且小于400,则诊断成功

Pod重启策略

Pod一旦配置探针,在检测失败时候,会基于restartPolicy对Pod进行下一步操作,restartPolicy(容器重启策略):

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

容器启动过程中类型

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

探针通用配置参数

存活探针和就绪探针都适用以下参数配置

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

探针http配置参数

HTTP探测器可以在 httpGet 上配置额外的字段:

host:#连接使用的主机名,默认是Pod的IP,也可以在HTTP头中设置“Host”来代替。

scheme: http #用于设置连接主机的方式(HTTP还是HTTPS),默认是HTTP。

path: /monitorlindex.html #访问HTTP服务的路径。

port: 80 #访问容器的端口号或者端口名,如果数字必须在1 ~65535之间。

案例一 基于http的检测

创建pod

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: 3
          successThreshold: 1
          failureThreshold: 3

        readinessProbe:    #就绪探针,检测失败会被从service中摘除
          httpGet:
            #path: /monitor/monitor.html
            path: /index.html
            port: 80
          initialDelaySeconds: 5
          periodSeconds: 3
          timeoutSeconds: 3
          successThreshold: 1
          failureThreshold: 3

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

验证

案例二 基于TCP检测

对没有http访问接口的服务进行检测如redis、mysql等,通常检测方法是端口是否存在。

创建pod

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: 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

案例三 命令探测

创建pod

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

验证

 案例五 postStart

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:
      terminationGracePeriodSeconds: 60
      containers:
      - name: myserver-myapp-frontend-label
        image: nginx:1.20.2
        ports:
        - containerPort: 80
        startupProbe:    #检测失败不会执行下一步,且只会检测一次
          httpGet:
            #path: /monitor/index.html
            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

检测

  Startup probe检测失败不会执行下一个探针,会重启

案例六 preStop

在pod被执行前执行,用来优雅停止pod,不影响用户访问。

面试常见问题:使用preStop来进行优雅停止进程防止流量进来

Pod终止流程

创建pod完成调度流程----》容器启动并执行postStart、livenessProbe----》进入running状态----》readinessProbeservice关联pod接受客户端请求
删除pod----》Pod被设置为”Terminating”状态、从service的Endpoints列表中删除并不再接受客户端请求----》执行PreStop----》Kubernetes向pod中的容器发送SIGTERM信号(正常终止信号)终止pod里面的主进程,这个信号让容器知道自己很快将会被关闭----》terminationGracePeriodSeconds: 60 #可选终止等待期,如果有设置删除宽限时间,则等待宽限时间到期,否则最多等待30s。Kubernetes等待指定的时间称为优雅终止宽限期,默认情况下是30秒,值得注意的是等待期与preStop Hook和SIGTERM信号并行执行,即Kubernetes可能不会等待preStop Hook完成(最长30秒之后主进程还没有结束就就强制终止pod)。----》SIGKILL信号被发送到Pod,并删除Pod

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 #可选终止等待期,如果有设置删除宽限时间,则等待宽限时间到期,否则最多等待30s。Kubernetes等待指定的时间称为优雅终止宽限期,默认情况下是30秒,值得注意的是等待期与preStop Hook和SIGTERM信号并行执行,即Kubernetes可能不会等待preStop Hook完成(最长30秒之后主进程还没有结束就就强制终止pod)。
      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: ["/usr/local/tomcat/bin/catalina.sh","stop"]
        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

实战案例-自定义镜像运行Nginx及tomcat服务并基于NFS实现动静分离

构建centos基础镜像

编辑Dockfile文件

[root@k8s-master1 system]# cat Dockerfile 
FROM centos:7.8.2003
LABEL maintainer="834943551@qq.com"
ADD filebeat-7.12.1-x86_64.rpm /tmp
RUN yum install -y epel-release && yum install -y /tmp/filebeat-7.12.1-x86_64.rpm  vim wget tree lrzsz gcc gcc-c++ automake pcre pcre-devel zlib zlib-devel openssl openssl-devel iproute net-tools iotop &&   rm -rf /etc/localtime /tmp/filebeat-7.12.1-x86_64.rpm && ln -snf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime

#安装日志收集工具以及一些常用命令工具,设置时区

上传centos基础镜像

[root@k8s-master1 system]# cat build-command.sh 
#!/bin/bash
docker build -t  k8s-harbor.com/public/centos-base:7.8.2003 .

docker push k8s-harbor.com/public/centos-base:7.8.2003

构建jdk基础镜像 

编辑Dockfile文件

FROM k8s-harbor.com/public/centos-base:7.8.2003
LABEL maintainer="834943551@qq.com"
ADD jdk-8u212-linux-x64.tar.gz /usr/local/src/
RUN ln -sv /usr/local/src/jdk1.8.0_212 /usr/local/jdk

ADD profile /etc/profile


ENV JAVA_HOME /usr/local/jdk
ENV JRE_HOME $JAVA_HOME/jre
ENV CLASSPATH $JAVA_HOME/lib/:$JRE_HOME/lib/
ENV PATH $PATH:$JAVA_HOME/bin

#使用刚打好的centos镜像,添加jdk包并设置环境变量

上传jdk基础镜像

#!/bin/bash
docker build -t k8s-harbor.com/public/jdk-base:v8.212  .
sleep 1
docker push  k8s-harbor.com/public/jdk-base:v8.212

 构建nginx基础镜像 

编辑Dockfile文件

[root@k8s-master1 nginx]# cat Dockerfile 
#Nginx Base Image
FROM k8s-harbor.com/public/centos-base:7.8.2003

MAINTAINER  "834943551@qq.com"

ADD nginx-1.20.2.tar.gz /usr/local/src/
RUN cd /usr/local/src/nginx-1.20.2 && ./configure  && make && make install && ln -sv  /usr/local/nginx/sbin/nginx /usr/sbin/nginx  &&rm -rf /usr/local/src/nginx-1.20.2.tar.gz 
RUN useradd nginx -u 2022

#添加nginx包,解压并编译,设置nginx全局执行,并添加nginx普通用户

上传jdk基础镜像

[root@k8s-master1 nginx]# cat build-command.sh 
#!/bin/bash
docker build -t k8s-harbor.com/public/nginx-base:v1.20.2  .
sleep 1
docker push  k8s-harbor.com/public/nginx-base:v1.20.2

 

 构建tomcat基础镜像

编辑Dockfile文件

[root@k8s-master1 base]# cat Dockerfile 
#Tomcat 8.5.43基础镜像
FROM k8s-harbor.com/public/jdk-base:v8.212

LABEL maintainer="834943551@qq.com"

RUN mkdir /apps /data/tomcat/webapps /data/tomcat/logs -pv 
ADD apache-tomcat-8.5.43.tar.gz  /apps
RUN useradd tomcat -u 2050 && ln -sv /apps/apache-tomcat-8.5.43 /apps/tomcat && chown -R tomcat.tomcat /apps /data

上传tomcat基础镜像

[root@k8s-master1 base]# cat build-command.sh 
#!/bin/bash
docker build -t k8s-harbor.com/public/tomcat-base:v8.5.43  .
sleep 3
docker push  k8s-harbor.com/public/tomcat-base:v8.5.43

 

 创建以tomcat为基础镜像

准备工作

[root@k8s-master1 tomcat-app1]# cat Dockerfile 
#tomcat web1
FROM k8s-harbor.com/public/tomcat-base:v8.5.43

ADD catalina.sh /apps/tomcat/bin/catalina.sh
ADD server.xml /apps/tomcat/conf/server.xml    #修改了代码路径/data/tomcat/webapps
#ADD myapp/* /data/tomcat/webapps/myapp/
ADD app1.tar.gz /data/tomcat/webapps/myapp/
ADD run_tomcat.sh /apps/tomcat/bin/run_tomcat.sh
#ADD filebeat.yml /etc/filebeat/filebeat.yml 
RUN chown  -R tomcat.tomcat /data/ /apps/
RUN chmod +x /apps/tomcat/bin/*.sh
RUN chown  -R tomcat.tomcat /etc/hosts
#ADD filebeat-7.5.1-x86_64.rpm /tmp/
#RUN cd /tmp && yum localinstall -y filebeat-7.5.1-amd64.deb

EXPOSE 8080 8443

CMD ["/apps/tomcat/bin/run_tomcat.sh"]
[root@k8s-master1 tomcat-app1]# cat run_tomcat.sh 
#!/bin/bash
#echo "nameserver 223.6.6.6" > /etc/resolv.conf
#echo "192.168.7.248 k8s-vip.example.com" >> /etc/hosts

#/usr/share/filebeat/bin/filebeat -e -c /etc/filebeat/filebeat.yml -path.home /usr/share/filebeat -path.config /etc/filebeat -path.data /var/lib/filebeat -path.logs /var/log/filebeat &
su - tomcat -c "/apps/tomcat/bin/catalina.sh start"
tail -f /etc/hosts

#普通用户启动,一定要确保有执行权限,tail命令为守护进程

上传镜像

[root@k8s-master1 tomcat-app1]# cat build-command.sh 
#!/bin/bash
TAG=$1
docker build -t  k8s-harbor.com/project/tomcat-app1:${TAG} .
sleep 3
docker push  k8s-harbor.com/project/tomcat-app1:${TAG}

 

 

 通过K8S 实现nginx和tomcat动静分离

创建tomcat pod

root@k8s-master1 tomcat-app1]# cat tomcat-app1.yaml 
kind: Deployment
#apiVersion: extensions/v1beta1
apiVersion: apps/v1
metadata:
  labels:
    app: magedu-tomcat-app1-deployment-label
  name: magedu-tomcat-app1-deployment
  namespace: magedu
spec:
  replicas: 2
  selector:
    matchLabels:
      app: magedu-tomcat-app1-selector
  template:
    metadata:
      labels:
        app: magedu-tomcat-app1-selector
    spec:
      containers:
      - name: magedu-tomcat-app1-container
        image: k8s-harbor.com/project/tomcat-app1:202205041638
        #command: ["/apps/tomcat/bin/run_tomcat.sh"]
        imagePullPolicy: IfNotPresent
        #imagePullPolicy: Always
      #imagePullSecrets:
      #- name: aliyun-registry-image-pull-key       
        ports:
        - containerPort: 8080
          protocol: TCP
          name: http
        env:
        - name: "password"
          value: "123456"
        - name: "age"
          value: "18"
        resources:
          limits:
            cpu: 1
            memory: "512Mi"
          requests:
            cpu: 500m
            memory: "512Mi"
        volumeMounts:
        - name: magedu-images
          mountPath: /data/tomcat/webapps/images
          readOnly: false
        - name: magedu-static
          mountPath: /data/tomcat/webapps/static
          readOnly: false
      volumes:
      - name: magedu-images
        nfs:
          server: 192.168.226.144
          path: /data/k8sdata/magedu/images
      - name: magedu-static
        nfs:
          server: 192.168.226.144
          path: /data/k8sdata/magedu/static
#      nodeSelector:
#        project: magedu
#        app: tomcat
      imagePullSecrets:
        - name: aliyun-registry-image-pull-key
---
kind: Service
apiVersion: v1
metadata:
  labels:
    app: magedu-tomcat-app1-service-label
  name: magedu-tomcat-app1-service
  namespace: magedu
spec:
  #type: NodePort
  ports:
  - name: http
    port: 80
    protocol: TCP
    targetPort: 8080
    #nodePort: 30092
  selector:
    app: magedu-tomcat-app1-selector

构建nginx镜像

修改nginx配置
upstream  tomcat_webserver {
        server  magedu-tomcat-app1-service.magedu.svc.k8s.local:80;
}

    server {
        listen       80;
        server_name  localhost;

        #charset koi8-r;

        #access_log  logs/host.access.log  main;

        location / {
            root   html;
            index  index.html index.htm;
        }

        location /webapp {
            root   html;
            index  index.html index.htm;
        }

        location /myapp {
             proxy_pass  http://tomcat_webserver;
             proxy_set_header   Host    $host;
             proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
             proxy_set_header X-Real-IP $remote_addr;
        }
[root@k8s-master1 app1]# cat Dockerfile
#Nginx 1.20.2
FROM k8s-harbor.com/public/nginx-base:v1.20.2


RUN useradd tomcat -u 2050 
ADD nginx.conf /usr/local/nginx/conf/nginx.conf
ADD app1.tar.gz  /usr/local/nginx/html/webapp/
ADD index.html  /usr/local/nginx/html/index.html
ADD run_tomcat.sh /usr/local/nginx/sbin/

#静态资源挂载路径
RUN mkdir -p /usr/local/nginx/html/webapp/static /usr/local/nginx/html/webapp/images && chown tomcat.tomcat -R /usr/local/nginx/html/webapp/static /usr/local/nginx/html/webapp/images 

EXPOSE 80 443

CMD ["/usr/local/nginx/sbin/run_tomcat.sh"] 
#CMD ["nginx"]


[root@k8s-master1 app1]# cat run_tomcat.sh 
#!/bin/bash
/usr/local/nginx/sbin/nginx
tail -f /etc/hosts

创建nginx pod

[root@k8s-master1 nginx]# cat nginx.yaml 
kind: Deployment
apiVersion: apps/v1
metadata:
  labels:
    app: magedu-nginx-deployment-label
  name: magedu-nginx-deployment
  namespace: magedu
spec:
  replicas: 1
  selector:
    matchLabels:
      app: magedu-nginx-selector
  template:
    metadata:
      labels:
        app: magedu-nginx-selector
    spec:
      containers:
      - name: magedu-nginx-container
        image: k8s-harbor.com/project/nginx-web1:202205041902
        #command: ["/apps/tomcat/bin/run_tomcat.sh"]
        #imagePullPolicy: IfNotPresent
        imagePullPolicy: Always
        ports:
        - containerPort: 80
          protocol: TCP
          name: http
        - containerPort: 443
          protocol: TCP
          name: https
        env:
        - name: "password"
          value: "123456"
        - name: "age"
          value: "20"
        resources:
          limits:
            cpu: 100m
            memory: 100Mi
          requests:
            cpu: 100m
            memory: 100Mi

        volumeMounts:
        - name: magedu-images
          mountPath: /usr/local/nginx/html/webapp/images
          readOnly: false
        - name: magedu-static
          mountPath: /usr/local/nginx/html/webapp/static
          readOnly: false
      volumes:
      - name: magedu-images
        nfs:
          server: 192.168.226.144
          path: /data/k8sdata/magedu/images 
      - name: magedu-static
        nfs:
          server: 192.168.226.144
          path: /data/k8sdata/magedu/static
      #nodeSelector:
      #  group: magedu
      imagePullSecrets:
        - name: aliyun-registry-image-pull-key
    

---
kind: Service
apiVersion: v1
metadata:
  labels:
    app: magedu-nginx-service-label
  name: magedu-nginx-service
  namespace: magedu
spec:
  type: NodePort
  ports:
  - name: http
    port: 80
    protocol: TCP
    targetPort: 80
    nodePort: 30090
  - name: https
    port: 443
    protocol: TCP
    targetPort: 443
    nodePort: 30099
  selector:
    app: magedu-nginx-selector

修改负载均衡配置

listen k8s_linux66_tomcat_80
   bind 192.168.226.202:80
   mode tcp
   server node1 192.168.226.145:30090 check inter 2000 fall 3 rise 5
   server node2 192.168.226.146:30090 check inter 2000 fall 3 rise 5

验证

 

静态文件转发到nginx,动态通过nginx转发到tomcat

Logo

K8S/Kubernetes社区为您提供最前沿的新闻资讯和知识内容

更多推荐