mirror of
https://github.com/kubeshark/kubeshark.git
synced 2025-09-01 18:47:39 +00:00
Update tap targets over ws (#901)
Update tappers via websocket instead of by env var. This way the DaemonSet doesn't have to be applied just to notify the tappers that the tap targets changed. The number of tapper restarts is reduced. The DaemonSet still gets applied when there is a need to add/remove a tapper from a node.
This commit is contained in:
committed by
GitHub
parent
41a7587088
commit
a5c35d7d90
@@ -5,7 +5,6 @@ const (
|
||||
SyncEntriesConfigEnvVar = "SYNC_ENTRIES_CONFIG"
|
||||
HostModeEnvVar = "HOST_MODE"
|
||||
NodeNameEnvVar = "NODE_NAME"
|
||||
TappedAddressesPerNodeDictEnvVar = "TAPPED_ADDRESSES_PER_HOST"
|
||||
ConfigDirPath = "/app/config/"
|
||||
DataDirPath = "/app/data/"
|
||||
ValidationRulesFileName = "validation-rules.yaml"
|
||||
|
@@ -31,7 +31,8 @@ type MizuTapperSyncer struct {
|
||||
TapPodChangesOut chan TappedPodChangeEvent
|
||||
TapperStatusChangedOut chan shared.TapperStatus
|
||||
ErrorOut chan K8sTapManagerError
|
||||
nodeToTappedPodMap map[string][]core.Pod
|
||||
nodeToTappedPodMap shared.NodeToPodsMap
|
||||
tappedNodes []string
|
||||
}
|
||||
|
||||
type TapperSyncerConfig struct {
|
||||
@@ -177,7 +178,7 @@ func (tapperSyncer *MizuTapperSyncer) watchPodsForTapping() {
|
||||
podWatchHelper := NewPodWatchHelper(tapperSyncer.kubernetesProvider, &tapperSyncer.config.PodFilterRegex)
|
||||
eventChan, errorChan := FilteredWatch(tapperSyncer.context, podWatchHelper, tapperSyncer.config.TargetNamespaces, podWatchHelper)
|
||||
|
||||
restartTappers := func() {
|
||||
handleChangeInPods := func() {
|
||||
err, changeFound := tapperSyncer.updateCurrentlyTappedPods()
|
||||
if err != nil {
|
||||
tapperSyncer.ErrorOut <- K8sTapManagerError{
|
||||
@@ -197,7 +198,7 @@ func (tapperSyncer *MizuTapperSyncer) watchPodsForTapping() {
|
||||
}
|
||||
}
|
||||
}
|
||||
restartTappersDebouncer := debounce.NewDebouncer(updateTappersDelay, restartTappers)
|
||||
restartTappersDebouncer := debounce.NewDebouncer(updateTappersDelay, handleChangeInPods)
|
||||
|
||||
for {
|
||||
select {
|
||||
@@ -295,6 +296,20 @@ func (tapperSyncer *MizuTapperSyncer) updateCurrentlyTappedPods() (err error, ch
|
||||
}
|
||||
|
||||
func (tapperSyncer *MizuTapperSyncer) updateMizuTappers() error {
|
||||
nodesToTap := make([]string, len(tapperSyncer.nodeToTappedPodMap))
|
||||
i := 0
|
||||
for node := range tapperSyncer.nodeToTappedPodMap {
|
||||
nodesToTap[i] = node
|
||||
i++
|
||||
}
|
||||
|
||||
if shared.EqualStringSlices(nodesToTap, tapperSyncer.tappedNodes) {
|
||||
logger.Log.Debug("Skipping apply, DaemonSet is up to date")
|
||||
return nil
|
||||
}
|
||||
|
||||
logger.Log.Debugf("Updating DaemonSet to run on nodes: %v", nodesToTap)
|
||||
|
||||
if len(tapperSyncer.nodeToTappedPodMap) > 0 {
|
||||
var serviceAccountName string
|
||||
if tapperSyncer.config.MizuServiceAccountExists {
|
||||
@@ -303,6 +318,11 @@ func (tapperSyncer *MizuTapperSyncer) updateMizuTappers() error {
|
||||
serviceAccountName = ""
|
||||
}
|
||||
|
||||
nodeNames := make([]string, 0, len(tapperSyncer.nodeToTappedPodMap))
|
||||
for nodeName := range tapperSyncer.nodeToTappedPodMap {
|
||||
nodeNames = append(nodeNames, nodeName)
|
||||
}
|
||||
|
||||
if err := tapperSyncer.kubernetesProvider.ApplyMizuTapperDaemonSet(
|
||||
tapperSyncer.context,
|
||||
tapperSyncer.config.MizuResourcesNamespace,
|
||||
@@ -310,7 +330,7 @@ func (tapperSyncer *MizuTapperSyncer) updateMizuTappers() error {
|
||||
tapperSyncer.config.AgentImage,
|
||||
TapperPodName,
|
||||
fmt.Sprintf("%s.%s.svc.cluster.local", ApiServerPodName, tapperSyncer.config.MizuResourcesNamespace),
|
||||
tapperSyncer.nodeToTappedPodMap,
|
||||
nodeNames,
|
||||
serviceAccountName,
|
||||
tapperSyncer.config.TapperResources,
|
||||
tapperSyncer.config.ImagePullPolicy,
|
||||
@@ -335,5 +355,7 @@ func (tapperSyncer *MizuTapperSyncer) updateMizuTappers() error {
|
||||
logger.Log.Debugf("Successfully reset tapper daemon set")
|
||||
}
|
||||
|
||||
tapperSyncer.tappedNodes = nodesToTap
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@@ -708,18 +708,13 @@ func (provider *Provider) CreateConfigMap(ctx context.Context, namespace string,
|
||||
return nil
|
||||
}
|
||||
|
||||
func (provider *Provider) ApplyMizuTapperDaemonSet(ctx context.Context, namespace string, daemonSetName string, podImage string, tapperPodName string, apiServerPodIp string, nodeToTappedPodMap map[string][]core.Pod, serviceAccountName string, resources shared.Resources, imagePullPolicy core.PullPolicy, mizuApiFilteringOptions api.TrafficFilteringOptions, logLevel logging.Level, serviceMesh bool, tls bool) error {
|
||||
logger.Log.Debugf("Applying %d tapper daemon sets, ns: %s, daemonSetName: %s, podImage: %s, tapperPodName: %s", len(nodeToTappedPodMap), namespace, daemonSetName, podImage, tapperPodName)
|
||||
func (provider *Provider) ApplyMizuTapperDaemonSet(ctx context.Context, namespace string, daemonSetName string, podImage string, tapperPodName string, apiServerPodIp string, nodeNames []string, serviceAccountName string, resources shared.Resources, imagePullPolicy core.PullPolicy, mizuApiFilteringOptions api.TrafficFilteringOptions, logLevel logging.Level, serviceMesh bool, tls bool) error {
|
||||
logger.Log.Debugf("Applying %d tapper daemon sets, ns: %s, daemonSetName: %s, podImage: %s, tapperPodName: %s", len(nodeNames), namespace, daemonSetName, podImage, tapperPodName)
|
||||
|
||||
if len(nodeToTappedPodMap) == 0 {
|
||||
if len(nodeNames) == 0 {
|
||||
return fmt.Errorf("daemon set %s must tap at least 1 pod", daemonSetName)
|
||||
}
|
||||
|
||||
nodeToTappedPodMapJsonStr, err := json.Marshal(nodeToTappedPodMap)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
mizuApiFilteringOptionsJsonStr, err := json.Marshal(mizuApiFilteringOptions)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -773,7 +768,6 @@ func (provider *Provider) ApplyMizuTapperDaemonSet(ctx context.Context, namespac
|
||||
agentContainer.WithEnv(
|
||||
applyconfcore.EnvVar().WithName(shared.LogLevelEnvVar).WithValue(logLevel.String()),
|
||||
applyconfcore.EnvVar().WithName(shared.HostModeEnvVar).WithValue("1"),
|
||||
applyconfcore.EnvVar().WithName(shared.TappedAddressesPerNodeDictEnvVar).WithValue(string(nodeToTappedPodMapJsonStr)),
|
||||
applyconfcore.EnvVar().WithName(shared.GoGCEnvVar).WithValue("12800"),
|
||||
applyconfcore.EnvVar().WithName(shared.MizuFilteringOptionsEnvVar).WithValue(string(mizuApiFilteringOptionsJsonStr)),
|
||||
)
|
||||
@@ -811,10 +805,6 @@ func (provider *Provider) ApplyMizuTapperDaemonSet(ctx context.Context, namespac
|
||||
agentResources := applyconfcore.ResourceRequirements().WithRequests(agentResourceRequests).WithLimits(agentResourceLimits)
|
||||
agentContainer.WithResources(agentResources)
|
||||
|
||||
nodeNames := make([]string, 0, len(nodeToTappedPodMap))
|
||||
for nodeName := range nodeToTappedPodMap {
|
||||
nodeNames = append(nodeNames, nodeName)
|
||||
}
|
||||
nodeSelectorRequirement := applyconfcore.NodeSelectorRequirement()
|
||||
nodeSelectorRequirement.WithKey("kubernetes.io/hostname")
|
||||
nodeSelectorRequirement.WithOperator(core.NodeSelectorOpIn)
|
||||
|
@@ -5,12 +5,11 @@ import (
|
||||
|
||||
"github.com/up9inc/mizu/shared"
|
||||
core "k8s.io/api/core/v1"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
func GetNodeHostToTappedPodsMap(tappedPods []core.Pod) map[string][]core.Pod {
|
||||
nodeToTappedPodMap := make(map[string][]core.Pod)
|
||||
func GetNodeHostToTappedPodsMap(tappedPods []core.Pod) shared.NodeToPodsMap {
|
||||
nodeToTappedPodMap := make(shared.NodeToPodsMap)
|
||||
for _, pod := range tappedPods {
|
||||
minimizedPod := getMinimizedPod(pod)
|
||||
|
||||
@@ -29,18 +28,18 @@ func getMinimizedPod(fullPod core.Pod) core.Pod {
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: fullPod.Name,
|
||||
},
|
||||
Status: v1.PodStatus{
|
||||
Status: core.PodStatus{
|
||||
PodIP: fullPod.Status.PodIP,
|
||||
ContainerStatuses: getMinimizedContainerStatuses(fullPod),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func getMinimizedContainerStatuses(fullPod core.Pod) []v1.ContainerStatus {
|
||||
result := make([]v1.ContainerStatus, len(fullPod.Status.ContainerStatuses))
|
||||
func getMinimizedContainerStatuses(fullPod core.Pod) []core.ContainerStatus {
|
||||
result := make([]core.ContainerStatus, len(fullPod.Status.ContainerStatuses))
|
||||
|
||||
for i, container := range fullPod.Status.ContainerStatuses {
|
||||
result[i] = v1.ContainerStatus{
|
||||
result[i] = core.ContainerStatus{
|
||||
ContainerID: container.ContainerID,
|
||||
}
|
||||
}
|
||||
|
@@ -6,24 +6,25 @@ import (
|
||||
|
||||
"github.com/op/go-logging"
|
||||
"github.com/up9inc/mizu/shared/logger"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
|
||||
"gopkg.in/yaml.v3"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
)
|
||||
|
||||
type WebSocketMessageType string
|
||||
|
||||
const (
|
||||
WebSocketMessageTypeEntry WebSocketMessageType = "entry"
|
||||
WebSocketMessageTypeFullEntry WebSocketMessageType = "fullEntry"
|
||||
WebSocketMessageTypeTappedEntry WebSocketMessageType = "tappedEntry"
|
||||
WebSocketMessageTypeUpdateStatus WebSocketMessageType = "status"
|
||||
WebSocketMessageTypeAnalyzeStatus WebSocketMessageType = "analyzeStatus"
|
||||
WebsocketMessageTypeOutboundLink WebSocketMessageType = "outboundLink"
|
||||
WebSocketMessageTypeToast WebSocketMessageType = "toast"
|
||||
WebSocketMessageTypeQueryMetadata WebSocketMessageType = "queryMetadata"
|
||||
WebSocketMessageTypeStartTime WebSocketMessageType = "startTime"
|
||||
WebSocketMessageTypeTapConfig WebSocketMessageType = "tapConfig"
|
||||
WebSocketMessageTypeEntry WebSocketMessageType = "entry"
|
||||
WebSocketMessageTypeFullEntry WebSocketMessageType = "fullEntry"
|
||||
WebSocketMessageTypeTappedEntry WebSocketMessageType = "tappedEntry"
|
||||
WebSocketMessageTypeUpdateStatus WebSocketMessageType = "status"
|
||||
WebSocketMessageTypeUpdateTappedPods WebSocketMessageType = "tappedPods"
|
||||
WebSocketMessageTypeAnalyzeStatus WebSocketMessageType = "analyzeStatus"
|
||||
WebsocketMessageTypeOutboundLink WebSocketMessageType = "outboundLink"
|
||||
WebSocketMessageTypeToast WebSocketMessageType = "toast"
|
||||
WebSocketMessageTypeQueryMetadata WebSocketMessageType = "queryMetadata"
|
||||
WebSocketMessageTypeStartTime WebSocketMessageType = "startTime"
|
||||
WebSocketMessageTypeTapConfig WebSocketMessageType = "tapConfig"
|
||||
)
|
||||
|
||||
type Resources struct {
|
||||
@@ -75,11 +76,29 @@ type WebSocketStatusMessage struct {
|
||||
TappingStatus []TappedPodStatus `json:"tappingStatus"`
|
||||
}
|
||||
|
||||
type WebSocketTappedPodsMessage struct {
|
||||
*WebSocketMessageMetadata
|
||||
NodeToTappedPodMap NodeToPodsMap `json:"nodeToTappedPodMap"`
|
||||
}
|
||||
|
||||
type WebSocketTapConfigMessage struct {
|
||||
*WebSocketMessageMetadata
|
||||
TapTargets []v1.Pod `json:"pods"`
|
||||
}
|
||||
|
||||
type NodeToPodsMap map[string][]v1.Pod
|
||||
|
||||
func (np NodeToPodsMap) Summary() map[string][]string {
|
||||
summary := make(map[string][]string)
|
||||
for node, pods := range np {
|
||||
for _, pod := range pods {
|
||||
summary[node] = append(summary[node], pod.Namespace + "/" + pod.Name)
|
||||
}
|
||||
}
|
||||
|
||||
return summary
|
||||
}
|
||||
|
||||
type TapperStatus struct {
|
||||
TapperName string `json:"tapperName"`
|
||||
NodeName string `json:"nodeName"`
|
||||
@@ -121,6 +140,15 @@ func CreateWebSocketStatusMessage(tappedPodsStatus []TappedPodStatus) WebSocketS
|
||||
}
|
||||
}
|
||||
|
||||
func CreateWebSocketTappedPodsMessage(nodeToTappedPodMap NodeToPodsMap) WebSocketTappedPodsMessage {
|
||||
return WebSocketTappedPodsMessage{
|
||||
WebSocketMessageMetadata: &WebSocketMessageMetadata{
|
||||
MessageType: WebSocketMessageTypeUpdateTappedPods,
|
||||
},
|
||||
NodeToTappedPodMap: nodeToTappedPodMap,
|
||||
}
|
||||
}
|
||||
|
||||
func CreateWebSocketMessageTypeAnalyzeStatus(analyzeStatus AnalyzeStatus) WebSocketAnalyzeStatusMessage {
|
||||
return WebSocketAnalyzeStatusMessage{
|
||||
WebSocketMessageMetadata: &WebSocketMessageMetadata{
|
||||
|
@@ -32,3 +32,17 @@ func Unique(slice []string) []string {
|
||||
|
||||
return list
|
||||
}
|
||||
|
||||
func EqualStringSlices(slice1 []string, slice2 []string) bool {
|
||||
if len(slice1) != len(slice2) {
|
||||
return false
|
||||
}
|
||||
|
||||
for _, v := range slice1 {
|
||||
if !Contains(slice2, v) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
Reference in New Issue
Block a user