解决方案:filebeat采集容器日志时根据kubernetes元数据限定采集源的问题

优采云 发布时间: 2022-11-27 17:23

  解决方案:filebeat采集容器日志时根据kubernetes元数据限定采集源的问题

  使用filebeat采集部署在腾讯云容器服务容器集群上的日志时,会采集default、kube-system等默认命名空间下的日志,但这些命名空间下的日志一般不是我们需要的。如何过滤掉这些命名空间下容器的运行日志?更直观的想法是在filebeat的yml配置中定义处理器,使用drop_event处理器丢弃采集

到的无用日志。这种方式虽然可以过滤日志,但是filebeat还是会采集

不需要采集

的容器日志。监控和采集一定程度上降低了filebeat的效率,那么有没有什么好的方法可以从源头上不采集不必要的日志呢?

  1.使用filebeat 7.x采集

容器日志

  对于容器日志的采集

,filebeat有两种特殊的inupt类型:docker和container。早期6.x版本的filebeat只有docker输入类型,对使用docker作为运行时组件的kubernetes集群更友好;在7.2版本Filebeat重新开发了container类型的input类型,无论是docker组件还是containerd组件,都能更好的支持。因此,从7.2版本开始,docker input已经被废弃,官方推荐使用container input。

  使用filebeat 7.x采集容器日志时,推荐使用container input,使用autodiscover实现容器的自动发现,即当有新容器运行时,filebeat会自动采集新创建的容器日志,而无需修改filebeat.yml即可实现新部署容器日志的采集

。官方使用autodiscover功能使得可以限制采集源,因为在autodiscover模式下,filebeat会调用kubernetes API获取当前集群下所有的namespace、pod、container等元数据信息,然后根据这些元数据去指定目录采集

对应的日志。

  下面给出一个可以限制获取源的文件beat.yml:

  filebeat.autodiscover:

providers:

- type: kubernetes

hints.enabled: true

templates:

- condition:

and:

- or:

- equals:

kubernetes.namespace: testa

- equals:

kubernetes.namespace: testb

- equals:

kubernetes.container.name: nginx

kubernetes.labels:

k8s-app: nginx

config:

- type: container

paths:

- /var/log/containers/${data.kubernetes.pod.name}_${data.kubernetes.namespace}_${data.kubernetes.container.name}-*.log

output.elasticsearch:

hosts: ['x.x.x.x:9200']

username: "xxx"

password: "xxx"

  上述配置中condition module下的部分用于限制采集源,用于限制只采集testa或testb命名空间下的nginx容器的日志。可以根据kubernetes元数据限制采集源。可用的元数据如下:

  host

port (if exposed)

kubernetes.labels

kubernetes.annotations

kubernetes.container.id

<p>

" />

kubernetes.container.image

kubernetes.container.name

kubernetes.namespace

kubernetes.node.name

kubernetes.pod.name

kubernetes.pod.uid

kubernetes.node.name

kubernetes.node.uid

kubernetes.namespace

kubernetes.service.name

kubernetes.service.uid

kubernetes.annotations

</p>

  上述配置中,condition可以根据需要定义更复杂的限制条件,可参照Conditions填写。

  另外需要注意的是,上述配置中config模块下的路径需要通过占位符匹配日志文件的名称,否则会出现采集到的日志内容与kubernetes元数据不一致的问题。例如/var/log/containers目录下有每个pod的日志,日志文件名的命名规则为{pod_name}_{namespace}_{container_name}-{container_id}.log

  nginx-6c5ff7b97b-6t5k4_default_nginx-eeecb30c81564668b1858c186099ab525431b435ed1b8fa3b25704cbbbca6a2d.log

  然后路径需要通过 $ 符号来匹配规则:

  ${data.kubernetes.pod.name}_${data.kubernetes.namespace}_${data.kubernetes.container.name}-*.log

  2.使用filebeat 6.x采集

容器日志

  6.x版本的filebeat只有docker input,对docker runtime组件比较友好,但是对containerd runtime组件不太友好。没有更好的办法限制采集源,只能全量采集所有容器的日志。

  2.1 采集docker组件部署的kubernetes集群中的容器日志:

  filebeat.autodiscover:

providers:

- type: kubernetes

templates:

- condition:

and:

- equals:

kubernetes.labels:

k8s-app: nginx

config:

- type: docker

<p>

" />

combine_partial: true

containers:

ids:

- ${data.kubernetes.container.id}

output.elasticsearch:

hosts: ['http://x.x.x.x:9200']

username: "xxxx"

password: "xxx"

</p>

  condition条件用于限制只采集label为k8s-app:nginx的容器的日志。

  2.2 采集containerd组件部署的kubernetes集群中的容器日志:

  filebeat.autodiscover:

providers:

- type: kubernetes

hints.enabled: true

templates:

- condition:

and:

- equals:

kubernetes.labels:

k8s-app: nginx

config:

- type: docker

combine_partial: true

symlinks: true

containers:

path: "/var/log/containers"

ids:

- ""

output.elasticsearch:

hosts: ['http://x.x.x.x:9200']

username: "xxx"

password: "xxxx"

  上面的配置和2.1中的配置不同的是,需要明确指定container.path为/var/log/containers,因为containerd组件下,container log在这个目录下,是软链接,需要指定symlinks: true,否则无法采集。另外container.ids需要指定为空字符串,不需要限制container id的匹配规则。该配置项对docker组件部署的容器有效,因为在docker组件下,容器日志默认在/var/lib/docker/containers目录下。,日志文件名以容器 ID 命名。

  上面配置的问题是condition条件不会生效,会全量采集

namespace下的所有容器日志。目前还没有找到很好的方案来限制采集源,但是可以通过定义一个drop_event processor来丢弃不需要采集的日志。实际使用中,建议直接使用filebeat 7.2及以上版本在部署了containerd组件的kubernetes集群中采集

容器日志。

  解决方案:多目标识别(监控自动识别物体)算法模型

  能够自动识别监控图像中的任何物体

  在监控中实现对图像画面的判断。(商业价值:打脸;监测移民的出入;识别不寻常的物体;对物体以外的物体等进行监控)。

  在需要通过模型加载的人员上训练人脸模型。在识别率优化的问题上,通过算法可以识别被屏蔽的人,防止监控,目前的遮挡识别率超过了其他同类识别算法。其中,对于监控摄像设备,它可以使用今天的普通摄像机。

  产品的展示效果

  代码区:

  客户

  从太平船务导入图片

  导入套接字

  导入简历2

  导入线程

  导入结构

  将 numpy 导入为 NP

  导入参数解析

  从 yolo *敏*感*词* YOLO, detect_video

  类Camera_Connect_Object:

  def init(self,D_addr_port=[“”,8880]):

  自我分辨率=[640,480]

  self.addr_port=D_addr_port

  self.src=888+15 #双方确定传输帧数,(888) 是校验值

  self.interval=0 #图片播放时间间隔

  self.img_fps=15 #每秒传输多少帧数

  def Set_socket(self):

self.client=socket.socket(socket.AF_INET,socket.SOCK_STREAM)

self.client.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)

def Socket_Connect(self):

self.Set_socket()

self.client.connect(self.addr_port)

print("IP is %s:%d" % (self.addr_port[0],self.addr_port[1]))

def RT_Image(self,yolo):

#按照格式打包发送帧数和分辨率

self.name=self.addr_port[0]+" Camera"

self.client.send(struct.pack("lhh", self.src, self.resolution[0], self.resolution[1]))

while(1):

info=struct.unpack("lhh",self.client.recv(8))

buf_size=info[0] #获取读的图片总长度

if buf_size:

try:

self.buf=b"" #代表bytes类型

temp_buf=self.buf

while(buf_size): #读取每一张图片的长度

temp_buf=self.client.recv(buf_size)

buf_size-=len(temp_buf)

self.buf+=temp_buf #获取图片

data = np.fromstring(self.buf, dtype=&#39;uint8&#39;) #按uint8转换为图像矩阵

self.image = cv2.imdecode(data, 1) #图像解码

imag = Image.fromarray(self.image)

imag = yolo.detect_image(imag)

result = np.asarray(imag)

cv2.putText(result, text=5, org=(3, 15), fontFace=cv2.FONT_HERSHEY_SIMPLEX,

fontScale=0.50, color=(255, 0, 0), thickness=2)

outVideo = cv2.resize(result, (640,480), interpolation=cv2.INTER_CUBIC)

# print(outVideo.shape)

# cv2.namedWindow("outVideo", cv2.WINDOW_NORMAL)

cv2.imshow(self.name, imag)

cv2.waitKey(10)

#cv2.imshow(self.name, self.image) #展示图片

yolo.close_session()

except:

pass;

finally:

if(cv2.waitKey(10)==27): #每10ms刷新一次图片,按‘ESC’(27)退出

self.client.close()

cv2.destroyAllWindows()

break

def Get_Data(self,interval):

showThread=threading.Thread(target=self.RT_Image(YOLO(**vars(FLAGS))))

showThread.start()

  如果名称 == 'main':

  # 类 YOLO 定义了默认值,因此在此处禁止任何默认值

  解析器 = 参数解析。参数解析器(argument_default=argparse.抑制)

  parser.add_argument('

  –model', type=str,

  help=&#39;模型权重文件的路径,默认值 &#39; + YOLO.get_defaults(“model_path”)

  )

  parser.add_argument(

&#39;--anchors&#39;, type=str,

help=&#39;path to anchor definitions, default &#39; + YOLO.get_defaults("anchors_path")

)

parser.add_argument(

&#39;--classes&#39;, type=str,

help=&#39;path to class definitions, default &#39; + YOLO.get_defaults("classes_path")

)

parser.add_argument(

&#39;--gpu_num&#39;, type=int,

help=&#39;Number of GPU to use, default &#39; + str(YOLO.get_defaults("gpu_num"))

)

parser.add_argument(

&#39;--image&#39;, default=False, action="store_true",

help=&#39;Image detection mode, will ignore all positional arguments&#39;

)

parser.add_argument(

&#39;--webcam&#39;, type=int,

help=&#39;Number of GPU to use, default &#39; + str(YOLO.get_defaults("webcam"))

)

&#39;&#39;&#39;

Command line positional arguments -- for video detection mode

&#39;&#39;&#39;

parser.add_argument(

"--input", nargs=&#39;?&#39;, type=str, required=False, default=&#39;./path2your_video&#39;,

help="Video input path"

)

parser.add_argument(

"--output", nargs=&#39;?&#39;, type=str, default="",

help="[Optional] Video output path"

)

<p>

" />

FLAGS = parser.parse_args()

print(FLAGS)

if FLAGS.image:

"""

Image detection mode, disregard any remaining command line arguments

"""

print("Image detection mode")

if "input" in FLAGS:

print(" Ignoring remaining command line arguments: " + FLAGS.input + "," + FLAGS.output)

camera=Camera_Connect_Object()

camera.addr_port[0]="192.168.1.100"

camera.addr_port=tuple(camera.addr_port)

camera.Socket_Connect()

camera.Get_Data(camera.interval)

</p>

  -- 编码: UTF-8 -

  通过读取 ui 文件 'jisuanji.ui' 生成的表单实现 # # 创建者: PyQt5 UI 代码*敏*感*词* 5.5.1 # # 警告!在此文件中所做的所有更改都将丢失!

  导入简历2

  导入操作系统

  导入系统

  from PyQt5.QtWidgets import QWidget, QPushButton, QApplication

  从 PyQt5.QtCore 导入 QCoreApplication

  从 PyQt5 导入 QtCore、QtGui、QtWidgets

  从 PyQt5.QtGui 导入 *

  从 PyQt5.QtWidgets 导入 *

  从 PyQt5.QtCore 导入 *

  从 PyQt5.QtCore import QTimer

  导入随机

  导入时间

  导入global_image

  将 numpy 导入为 NP

  global_image._init()

  类Ui_MainWindow(QMainWindow, QWidget):

  def init(self):super()

  .init()

   self.desktop = QApplication.desktop()

self.screenRect = self.desktop.screenGeometry()

self.height = self.screenRect.height()

self.width = self.screenRect.width()

self.video_width = int(self.width * 50 / 92 / 4) * 4

self.video_height = int(self.width * 50 / 92 / 4) * 3

self.vidofram = &#39;视频大小 : &#39; + str(self.video_width) + &#39; x &#39; + str(self.video_height)

self.setupUi(self)

self.timercount = 0

QShortcut(QKeySequence("Escape"), self, self.close)

self.showFullScreen()

self.videothread = VideoThread()

self.videothread.update_image_singal.connect(self.slot_init)

# self.videothread.finished.connect(self.slot_init())

self.videothread.start()

def setupUi(self, MainWindow):

MainWindow.setObjectName("MainWindow")

MainWindow.resize(self.width, self.height)

self.Mainwidget = QtWidgets.QWidget(MainWindow)

self.Mainwidget.setStyleSheet("#Mainwidget{border-image: url(./background8.png);}")

self.Mainwidget.setObjectName("Mainwidget")

self.verticalLayout = QtWidgets.QVBoxLayout(self.Mainwidget)

self.verticalLayout.setContentsMargins(0, -1, 0, 0)

# self.verticalLayout.setSpacing(0)

self.verticalLayout.setObjectName("verticalLayout")

self.horizontalLayout_up = QtWidgets.QHBoxLayout()

self.horizontalLayout_up.setContentsMargins(-1, -1, 0, 0)

self.horizontalLayout_up.setSpacing(0)

self.horizontalLayout_up.setObjectName("horizontalLayout_up")

spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)

self.horizontalLayout_up.addItem(spacerItem)

self.video_widget = QtWidgets.QWidget(self.Mainwidget)

self.video_widget.setObjectName("video_widget")

# self.video_widget.setStyleSheet("border-style:solid ;border-width: 1px 1px 1px 1px;border-color :white ;")

self.verticalLayout_video = QtWidgets.QVBoxLayout(self.video_widget)

self.verticalLayout_video.setObjectName("verticalLayout_video")

self.video = QtWidgets.QLabel(self.video_widget)

self.video.setObjectName("video")

self.verticalLayout_video.addWidget(self.video)

self.video.setMinimumSize(QtCore.QSize(self.video_width, self.video_height))

self.video.setMaximumSize(QtCore.QSize(self.video_width, self.video_height))

self.verticalLayout_video.setStretch(0, 1)

self.verticalLayout_video.setStretch(1, 30)

self.verticalLayout_video.setContentsMargins(400, 94, 4, 0)

self.horizontalLayout_up.addWidget(self.video_widget)

spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)

self.horizontalLayout_up.addItem(spacerItem1)

self.message_widget = QtWidgets.QWidget(self.Mainwidget)

self.message_widget.setObjectName("message_widget")

# self.message_widget.setStyleSheet("border-style:solid ;border-width: 1px 1px 1px 1px;border-color :white ;")

self.horizontalLayout_4 = QtWidgets.QHBoxLayout(self.message_widget)

self.horizontalLayout_4.setObjectName("horizontalLayout_4")

self.picture = QtWidgets.QLabel(self.message_widget)

self.picture.setMinimumSize(QtCore.QSize(320, 240))

self.picture.setMaximumSize(QtCore.QSize(320, 240))

self.picture.setObjectName("picture")

self.picture.setStyleSheet("border-style:solid ;border-width: 1px 1px 1px 1px;border-color :white ;")

####self.picture.setWindowOpacity(1)#透明背景色

self.picture.setScaledContents(True)

self.horizontalLayout_4.addWidget(self.picture)

self.horizontalLayout_up.addWidget(self.message_widget)

spacerItem2 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)

self.horizontalLayout_up.addItem(spacerItem2)

self.horizontalLayout_up.setStretch(0, 1)

self.horizontalLayout_up.setStretch(1, 61)

self.horizontalLayout_up.setStretch(2, 1)

self.horizontalLayout_up.setStretch(3, 30)

<p>

" />

self.horizontalLayout_up.setStretch(4, 2)

self.horizontalLayout_4.setContentsMargins(0, 180, 50, 100)

self.verticalLayout.addLayout(self.horizontalLayout_up)

self.horizontalLayout_down = QtWidgets.QHBoxLayout()

self.horizontalLayout_down.setContentsMargins(-1, -1, -1, 0)

# self.horizontalLayout_4.setContentsMargins(71, 21, 61, 39)

self.horizontalLayout_4.setSpacing(0)

self.horizontalLayout_down.setObjectName("horizontalLayout_down")

self.horizontalLayout_down.setContentsMargins(-1, -1, -1, 0)

self.verticalLayout.addLayout(self.horizontalLayout_down)

self.verticalLayout.setStretch(0, 40)

self.verticalLayout.setStretch(1, 1)

MainWindow.setCentralWidget(self.Mainwidget)

pe = QPalette()

pe.setColor(QPalette.WindowText, Qt.white) # 设置字体颜色

pegray = QPalette()

pegray.setColor(QPalette.WindowText, Qt.gray) # 设置字体颜色

font_viedo = QtGui.QFont()

font_viedo.setFamily("Microsoft YaHei")

font_viedo.setBold(True)

font_viedo.setPointSize(15)

self.video.setWordWrap(True)

self.video.setPalette(pegray)

self.video.setFont(font_viedo)

self.video.setStyleSheet("border-style:solid ;border-width: 1px 1px 1px 1px;border-color :white ;")

self.picture.setPalette(pegray)

self.picture.setFont(font_viedo)

self.retranslateUi(MainWindow)

QtCore.QMetaObject.connectSlotsByName(MainWindow)

self.timer = QTimer(self) # 初始化一个定时器

self.timer.timeout.connect(self.operate) # 计时结束调用operate()方法

self.timer.start(1000) # 设置计时间隔并启动

def retranslateUi(self, MainWindow):

_translate = QtCore.QCoreApplication.translate

MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))

self.video.setText(_translate("MainWindow", "\n\n\n\n\n\n\n\n\n\t\t\t\t 网络正在加载"))

self.picture.setText(_translate("MainWindow", "网片正在加载"))

def operate(self):

dot = [&#39;网络正在加载 .&#39;, &#39;网络正在加载 . .&#39;, &#39;网络正在加载 . . .&#39;, &#39;网络正在加载&#39;]

self.video.setText("\n\n\n\n\n\n\n\n\n\t\t\t\t " + dot[self.timercount])

self.timercount += 1

if self.timercount == 4:

self.timercount = 0

def mousePressEvent(self, event):

if event.button() == Qt.LeftButton:

print("鼠标左键点击")

global_image.Set_image_flag()

def slot_init(self, showImage, flag0):

if flag0 == False:

msg = QtWidgets.QMessageBox.warning(self, u"Warning", u"请检测相机与电脑是否连接正确")

# time.sleep(2)

quit()

else:

self.timer.stop()

self.video.setPixmap(QtGui.QPixmap.fromImage(showImage))

if global_image.Get_image_flag(): # 如果按下鼠标左键 就截图

self.picture.setPixmap(QtGui.QPixmap.fromImage(showImage))

####</p>

  ## 视频线程 #####

  class VideoThread(QtCore.QThread):

  update_image_singal = QtCore.pyqtSignal(QImage, bool)

  def init(self, parent=None):

  super(VideoThread, self).init(parent)

  self.desktop = QApplication.desktop()

  self.screenRect = self.desktop.screenGeometry()

  self.height = self.screenRect.height()

  self.width = self.screenRect.width()

  self.video_width = int(self.width * 50 / 91 / 4) * 4

  self.video_height = int(self.width * 50 / 91 / 4) * 3

  # self.video_width = 400

  # self.video_height = 300

  自我上限 = CV2。VideoCapture() # 创建一个 VideoCapture 对象

  def run(self):

self.flag0 = self.cap.open(0)

# if self.flag0 == False:

# return

while 1:

flag1, self.image = self.cap.read(0)

show = cv2.resize(self.image, (self.video_width, self.video_height))

show = cv2.cvtColor(show, cv2.COLOR_BGR2RGB)

showImage = QtGui.QImage(show.data, self.video_width, self.video_height, QtGui.QImage.Format_RGB888)

self.update_image_singal.emit(showImage, self.flag0)

# 两者总时间为子窗口显示时间

##

  ## 主 ###

  如果名称 == 'main':

  app = QApplication(sys.argv)

  UI = Ui_MainWindow()

  ui.show()

  sys.exit(app.exec_())

  导入labelgb_rc

  欢迎来电咨询

0 个评论

要回复文章请先登录注册


官方客服QQ群

微信人工客服

QQ人工客服


线