Enhance cilium fetcher with rules (#12419)

This commit is contained in:
mrproliu 2024-07-08 10:59:56 +00:00 committed by GitHub
parent 3acad529f5
commit 97f015ba4d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 222 additions and 5 deletions

View File

@ -72,6 +72,7 @@
<include>lal/*</include>
<include>log-mal-rules/**</include>
<include>telegraf-rules/*</include>
<include>cilium-rules/*</include>
</includes>
<outputDirectory>config</outputDirectory>
</fileSet>

View File

@ -53,6 +53,7 @@ layer-levels:
MYSQL: 2
POSTGRESQL: 2
MESH_DP: 1
CILIUM_SERVICE: 1
K8S_SERVICE: 0
```

View File

@ -34,6 +34,26 @@ cilium-fetcher:
3. `sslPrivateKeyFile`: the path of the private key file.
4. `sslCertChainFile`: the path of the certificate chain file.
5. `sslCaFile`: the path of the CA file.
3. Configure the cilium rules please configure the following configuration:
1. `cilium-rules/exclude.yaml`: Configure the which endpoint should be excluded from the monitoring, Please read [exclude rules selection](#exclude-rules) for more detail.
2. `cilium-rules/metadata-service-mapping.yaml`: Configure the service name and endpoint mapping.
### Exclude Rules
The exclude configuration in Cilium rules is used to specify which Cilium Endpoints would be excluded from being added to the topology map or from the generation of metrics and other data.
```yaml
namespaces: # define with traffic from which namespace should be excluded
- kube-system
labels: # define with traffic from which endpoint labels should be excluded, if matches any labels, the traffic would be excluded.
- k8s:io.cilium.k8s.namespace.labels.istio-injection: "enabled" # Each labels is a key-value pair, the key is the label key, the value is the label value.
k8s:security.istio.io/tlsMode: istio
```
By default, all the traffic from `kube-system` and traffic management by istio mesh would be excluded.
NOTE: Only the endpoint in both source and destination matches the exclude rules would be excluded. Otherwise, the traffic would be still included.
## Generated Entities

View File

@ -32,11 +32,14 @@ import org.apache.skywalking.oap.server.library.module.ModuleStartException;
import org.apache.skywalking.oap.server.library.module.ServiceNotProvidedException;
import org.apache.skywalking.oap.server.library.util.FieldsHelper;
import java.io.IOException;
@Slf4j
public class CiliumFetcherProvider extends ModuleProvider {
private CiliumFetcherConfig config;
protected String fieldMappingFile = "metadata-service-mapping.yaml";
protected String excludeRulesFile = "cilium-rules/exclude.yaml";
protected String fieldMappingFile = "cilium-rules/metadata-service-mapping.yaml";
@Override
public String name() {
@ -79,9 +82,15 @@ public class CiliumFetcherProvider extends ModuleProvider {
} catch (Exception e) {
throw new ModuleStartException(e.getMessage(), e);
}
ExcludeRules excludeRules;
try {
excludeRules = ExcludeRules.loadRules(excludeRulesFile);
} catch (IOException e) {
throw new ModuleStartException("loading exclude rules error", e);
}
final CiliumNodeManager ciliumNodeManager = new CiliumNodeManager(getManager(), new GrpcStubBuilder(config), config);
ciliumNodeManager.addListener(new CiliumFlowListener(getManager(), config));
ciliumNodeManager.addListener(new CiliumFlowListener(getManager(), config, excludeRules));
ciliumNodeManager.start();
}

View File

@ -0,0 +1,105 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.skywalking.oap.server.fetcher.cilium;
import io.cilium.api.flow.Endpoint;
import lombok.Data;
import org.apache.commons.lang3.StringUtils;
import org.apache.skywalking.oap.server.library.util.ResourceUtils;
import org.yaml.snakeyaml.Yaml;
import java.io.FileReader;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
public class ExcludeRules {
private final Set<String> namespaces;
private final List<Labels> labels;
public static ExcludeRules loadRules(final String path) throws IOException {
try (FileReader r = new FileReader(ResourceUtils.getPath(path).toFile())) {
final RuleYaml yaml = new Yaml().loadAs(r, RuleYaml.class);
return new ExcludeRules(yaml);
}
}
/**
* check if the endpoint should be excluded
*/
public boolean shouldExclude(Endpoint endpoint) {
// if the namespace is in the exclude list, return true
if (namespaces.contains(endpoint.getNamespace())) {
return true;
}
// if the endpoint has no labels, return false
if (endpoint.getLabelsCount() == 0) {
return false;
}
return labels.stream().anyMatch(label -> label.isMatch(endpoint));
}
private ExcludeRules(RuleYaml yaml) {
this.namespaces = Set.copyOf(yaml.getNamespaces());
this.labels = yaml.getLabels().stream().map(Labels::new).collect(Collectors.toList());
}
private static class Labels {
private Map<String, String> labelMap;
public Labels(Map<String, String> labelMap) {
this.labelMap = labelMap;
}
/**
* validate if the endpoint matches all the labels
*/
public boolean isMatch(Endpoint endpoint) {
int matchCount = 0;
for (Map.Entry<String, String> entry : labelMap.entrySet()) {
for (String endpointLabel : endpoint.getLabelsList()) {
// ignore when the key is not match
if (endpointLabel.indexOf(entry.getKey()) != 0) {
continue;
}
// ignore when the value is not match
if (!StringUtils.substring(endpointLabel, entry.getKey().length() + 1).equals(entry.getValue())) {
return false;
}
matchCount++;
// check the match count(full matched) to avoid unnecessary iteration
if (matchCount == labelMap.size()) {
return true;
}
}
}
return false;
}
}
@Data
public static class RuleYaml {
private List<String> namespaces;
private List<Map<String, String>> labels;
}
}

View File

@ -44,6 +44,7 @@ import org.apache.skywalking.oap.server.core.source.CiliumService;
import org.apache.skywalking.oap.server.core.source.CiliumServiceRelation;
import org.apache.skywalking.oap.server.core.source.SourceReceiver;
import org.apache.skywalking.oap.server.fetcher.cilium.CiliumFetcherConfig;
import org.apache.skywalking.oap.server.fetcher.cilium.ExcludeRules;
import org.apache.skywalking.oap.server.fetcher.cilium.nodes.CiliumNode;
import org.apache.skywalking.oap.server.fetcher.cilium.nodes.CiliumNodeUpdateListener;
import org.apache.skywalking.oap.server.library.module.ModuleManager;
@ -66,13 +67,15 @@ public class CiliumFlowListener implements CiliumNodeUpdateListener {
private final SourceReceiver sourceReceiver;
private final Integer retrySecond;
private final boolean convertClientAsServerTraffic;
private final ExcludeRules excludeRules;
public static final Layer SERVICE_LAYER = Layer.CILIUM_SERVICE;
public CiliumFlowListener(ModuleManager moduleManager, CiliumFetcherConfig config) {
public CiliumFlowListener(ModuleManager moduleManager, CiliumFetcherConfig config, ExcludeRules excludeRules) {
this.sourceReceiver = moduleManager.find(CoreModule.NAME).provider().getService(SourceReceiver.class);
this.retrySecond = config.getFetchFailureRetrySecond();
this.convertClientAsServerTraffic = config.isConvertClientAsServerTraffic();
this.excludeRules = excludeRules;
}
@Override
@ -357,6 +360,10 @@ public class CiliumFlowListener implements CiliumNodeUpdateListener {
if (this.convertClientAsServerTraffic && DetectPoint.SERVER.equals(parseDetectPoint(flow))) {
return true;
}
// ignore the flow when the source and dest endpoint should exclude both
if (excludeRules.shouldExclude(flow.getSource()) && excludeRules.shouldExclude(flow.getDestination())) {
return true;
}
return false;
}

View File

@ -320,6 +320,7 @@
<exclude>lal/</exclude>
<exclude>log-mal-rules/</exclude>
<exclude>telegraf-rules/</exclude>
<exclude>cilium-rules/</exclude>
</excludes>
</configuration>
</plugin>

View File

@ -0,0 +1,22 @@
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
namespaces:
- kube-system
labels:
- k8s:io.cilium.k8s.namespace.labels.istio-injection: enabled
k8s:security.istio.io/tlsMode: istio

View File

@ -0,0 +1,17 @@
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
serviceName: ${LABELS."service.istio.io/canonical-name",LABELS."app.kubernetes.io/name",LABELS.component,LABELS.app,LABELS.k8s-app}.${NAMESPACE}
serviceInstanceName: ${NAME}

View File

@ -74,6 +74,9 @@ hierarchy:
KAFKA: lower-short-name-with-fqdn
PULSAR: lower-short-name-with-fqdn
CILIUM_SERVICE:
K8S_SERVICE: short-name
# Use Groovy script to define the matching rules, the input parameters are the upper service(u) and the lower service(l) and the return value is a boolean,
# which are used to match the relation between the upper service(u) and the lower service(l) on the different layers.
auto-matching-rules:
@ -109,6 +112,7 @@ layer-levels:
ACTIVEMQ: 2
MESH_DP: 1
CILIUM_SERVICE: 1
K8S_SERVICE: 0

View File

@ -554,7 +554,37 @@
"layer": "CILIUM_SERVICE",
"entity": "Service",
"name": "Cilium-Service",
"isRoot": false
"isRoot": false,
"isDefault": true,
"expressions": [
"avg(cilium_service_l4_read_pkg_cpm)",
"avg(cilium_service_l4_write_pkg_cpm)",
"avg(cilium_service_protocol_cpm)",
"avg(cilium_service_protocol_call_duration/cilium_service_protocol_cpm)/1000000",
"avg(cilium_service_protocol_call_success_count/cilium_service_protocol_cpm*100)"
],
"expressionsConfig": [
{
"unit": "package / min",
"label": "Read"
},
{
"label": "Write",
"unit": "package / min"
},
{
"label": "Load",
"unit": "calls / min"
},
{
"label": "Latency",
"unit": "ms"
},
{
"label": "Success Rate",
"unit": "%"
}
]
}
}
]

@ -1 +1 @@
Subproject commit f664e786acead0bb1884d12f91635b2a1cb0fc47
Subproject commit fe6e853c57ffe690f799620be4b7393a4d2f7041