解决方案: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='uint8') #按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='模型权重文件的路径,默认值 ' + YOLO.get_defaults(“model_path”)
)
parser.add_argument(
'--anchors', type=str,
help='path to anchor definitions, default ' + YOLO.get_defaults("anchors_path")
)
parser.add_argument(
'--classes', type=str,
help='path to class definitions, default ' + YOLO.get_defaults("classes_path")
)
parser.add_argument(
'--gpu_num', type=int,
help='Number of GPU to use, default ' + str(YOLO.get_defaults("gpu_num"))
)
parser.add_argument(
'--image', default=False, action="store_true",
help='Image detection mode, will ignore all positional arguments'
)
parser.add_argument(
'--webcam', type=int,
help='Number of GPU to use, default ' + str(YOLO.get_defaults("webcam"))
)
'''
Command line positional arguments -- for video detection mode
'''
parser.add_argument(
"--input", nargs='?', type=str, required=False, default='./path2your_video',
help="Video input path"
)
parser.add_argument(
"--output", nargs='?', 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 = '视频大小 : ' + str(self.video_width) + ' x ' + 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 = ['网络正在加载 .', '网络正在加载 . .', '网络正在加载 . . .', '网络正在加载']
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
欢迎来电咨询