diff --git a/charts/lm-logs/.helmignore b/charts/lm-logs/.helmignore new file mode 100644 index 0000000..0e8a0eb --- /dev/null +++ b/charts/lm-logs/.helmignore @@ -0,0 +1,23 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/charts/lm-logs/Chart.yaml b/charts/lm-logs/Chart.yaml new file mode 100644 index 0000000..62c8247 --- /dev/null +++ b/charts/lm-logs/Chart.yaml @@ -0,0 +1,10 @@ +apiVersion: v2 +description: A Helm chart for sending k8s logs to Logic Monitor +name: lm-logs +icon: https://logicmonitor.github.io/helm-charts/lm_logo.png +version: 0.4.0 +maintainers: + - email: dev@logicmonitor.com + name: LogicMonitor +appVersion: 1.0.5 +home: https://logicmonitor.github.io/helm-charts diff --git a/charts/lm-logs/Dockerfile b/charts/lm-logs/Dockerfile new file mode 100644 index 0000000..2c92020 --- /dev/null +++ b/charts/lm-logs/Dockerfile @@ -0,0 +1,4 @@ +FROM fluent/fluentd-kubernetes-daemonset:v1.16-debian-forward-1 +USER root +RUN gem install fluent-plugin-lm-logs -v 1.0.5 +RUN gem install fluent-plugin-multi-format-parser -v 1.0.0 diff --git a/charts/lm-logs/README.md b/charts/lm-logs/README.md new file mode 100644 index 0000000..b05457e --- /dev/null +++ b/charts/lm-logs/README.md @@ -0,0 +1,78 @@ +## Send Kubernetes logs to LM Logs + +This chart deploy a fluentd based daemonset to collect and forward logs to LogicMonitor +#### Prerequisite +- LogicMonitor Collector [installed and monitoring your Kubernetes Cluster](https://www.logicmonitor.com/support/monitoring/containers/kubernetes/adding-your-kubernetes-cluster-into-monitoring). + +#### Deploy + +Install the lm-logs chart, filling in the required values. + +``` console +helm install -n \ +--set lm_company_name="" \ +--set lm_access_id="" \ +--set lm_access_key="" \ +lm-logs logicmonitor/lm-logs +``` + +#### Parameters +The following tables lists the configurable parameters of the lm-logs chart and their default values. +| Parameter | Description | Default | +|-----------------------------|-------------------------------------------------|---------------------------------------------------------| +| `global.imagePullSecrets` | List of global registry secret names | `[]` (does not add image pull secrets to deployed pods) | +| `global.nameOverride` | Global storage class for dynamic provisioning | `""` | +| `global.fullnameOverride` | Global storage class for dynamic provisioning | `""` | +| `global.lm_company_name` | LogicMonitor account name | `nil` | +| `global.lm_access_id` | LogicMonitor API Token Access ID | `nil` | +| `global.lm_access_key` | LogicMonitor API Token Access Key | `nil` | +| `image.repository` | Container image repository | `logicmonitor/lm-logs-k8s-fluentd` | +| `image.pullPolicy` | Container image pull policy | `IfNotPresent` | +| `image.tag` | Container image tag | `""` | +| `resources.limits.memory` | Container memory resource limit | `1000Mi` | +| `resources.requests.cpu.` | Container cpu resource requests | `300m` | +| `resources.requests.memory` | Container memory resource requests | `700Mi` | +| `fluent.device_less_logs` | beta feature. when set true, do not send resource information. send `service` and `namespace` as metadata when true | `false` | +| `fluent.include_metadata` | if true send all metadata along with log msg | `true` | +| `fluent.buffer.memory` | fluentd's buffer memory plugin config | `flush_interval 1s,chunk_limit_size 8m,flush_thread_count 8`| +| `tolerations` | Tolerations for pod assignment | `{}` (evaluated as a template) | +| `nodeSelectors` | Node labels for pod assignment | `{}` (evaluated as a template) | +| `affinity` | Affinity for pod assignment | `{}` (evaluated as a template) | +| `env` | Map to add extra environment variables | `{}` | +| `kubernetes.multiline_start_regexp` | Regexp to match beginning of multiline | `/^\[(\d{4}-)?\d{2}-\d{2} \d{2}:\d{2}:\d{2}.\d{3}.*\]/` | +| `kubernetes.cluster_name` | ClusterName given while adding k8s cluster | `""` | + +### Avaialble Environment variables +For descriptions see: https://github.com/fabric8io/fluent-plugin-kubernetes_metadata_filter + +* FLUENT_LOG_LEVEL +* FLUENT_CONTAINER_TAIL_TAG +* FLUENT_CONTAINER_TAIL_EXCLUDE_PATH +* FLUENT_CONTAINER_TAIL_PARSER_TYPE +* FLUENT_FILTER_KUBERNETES_URL +* KUBERNETES_VERIFY_SSL +* KUBERNETES_CA_FILE +* FLUENT_KUBERNETES_METADATA_SKIP_LABELS +* FLUENT_KUBERNETES_METADATA_SKIP_CONTAINER_METADATA +* FLUENT_KUBERNETES_METADATA_SKIP_MASTER_URL +* FLUENT_KUBERNETES_METADATA_SKIP_NAMESPACE_METADATA + +#### New deviceless logs k8s integration (beta) +Note: This feature may not be available to all customers. +To enable this feature set `fluent.device_less_logs=true` +##### Problems with current integration +- k8s pods are ephemeral, anomaly detection is done per pod. Which creates high volume of anomalies and makes it hard to monitor. +- When new pod is created, argus takes time to register it as LM Device and resource mapping fails until then. Consequently we miss initial pod logs. + +When `fluent.device_less_logs=true` +Anomaly detection will be done on `namespace` and `service` +- namespace will be k8s namespace +- service will be extracted from metadata for yaml in the following priority. + - kubernetets.labels.app ( deployments ) + - kubernetets.labels.app_kubernetes_io/name (daemon sets) + - kubernetets.container_name + - kubernetets.pod_name + +#### Multiline log support for k8s lm logs +To use regexp to match beginning of multiline set `kubernetes.multiline_start_regexp=` +by default the regex is set to `/^\[(\d{4}-)?\d{2}-\d{2} \d{2}:\d{2}:\d{2}.\d{3}.*\]/` diff --git a/charts/lm-logs/ci/base-sanity-values.yaml b/charts/lm-logs/ci/base-sanity-values.yaml new file mode 100644 index 0000000..3991170 --- /dev/null +++ b/charts/lm-logs/ci/base-sanity-values.yaml @@ -0,0 +1,3 @@ +lm_company_name: "dummy_company" +lm_access_id: "dummy_id" +lm_access_key: "dummy_key" diff --git a/charts/lm-logs/templates/_helpers.tpl b/charts/lm-logs/templates/_helpers.tpl new file mode 100644 index 0000000..2fe429e --- /dev/null +++ b/charts/lm-logs/templates/_helpers.tpl @@ -0,0 +1,119 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "fluentd.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "fluentd.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +Adding validations for clustername for lm-logs to contain only lower alphanumeric or '-' and start and end with an alphanumeric character +*/}} +{{- define "kubernetes.cluster_name" -}} +{{- $cluster := "" -}} +{{- if .Values.kubernetes.cluster_name -}} +{{- $cluster = .Values.kubernetes.cluster_name -}} +{{- else if .Values.global.clusterName -}} +{{- $cluster = .Values.global.clusterName -}} +{{- end -}} +{{- if ne $cluster "" -}} +{{- if regexMatch "^[a-z0-9][a-z0-9-]*[a-z0-9]$" $cluster }} +kubernetes.cluster_name {{ $cluster }} +{{- else -}} +{{- fail "cluster_name should contain only lower alphanumeric or '-' and should start and end with an alphanumeric character" }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "fluentd.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "fluentd.labels" -}} +helm.sh/chart: {{ include "fluentd.chart" . }} +app.kubernetes.io/component: lm-logs-agent +app.kubernetes.io/part-of: {{ template "fluentd.name" . }} +{{ include "fluentd.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- if .Values.labels }} +{{ toYaml .Values.labels }} +{{- end }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "fluentd.selectorLabels" -}} +app.kubernetes.io/name: {{ include "fluentd.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Common Annotations +*/}} +{{- define "fluentd.annotations" -}} +logicmonitor.com/provider: lm-container +{{- if .Values.annotations }} +{{ toYaml .Values.annotations }} +{{- end }} +{{- end }} + + +{{/* +Create the name of the service account to use +*/}} +{{- define "fluentd.serviceAccountName" -}} +{{- default (include "fluentd.fullname" .)}} +{{- end }} + +{{/* +Return the appropriate apiVersion for rbac. +*/}} +{{- define "rbac.apiVersion" -}} +{{- if .Capabilities.APIVersions.Has "rbac.authorization.k8s.io/v1" }} +{{- print "rbac.authorization.k8s.io/v1" -}} +{{- else -}} +{{- print "rbac.authorization.k8s.io/v1beta1" -}} +{{- end -}} +{{- end -}} + +{{- define "ds-env" -}} +{{- $envList := list -}} +{{- range $key, $val := .Values.env -}} +{{- $envProps := dict -}} +{{- $_ := set $envProps "name" $key -}} +{{- $_ = set $envProps "value" ($val) -}} +{{- $envList = append $envList $envProps -}} +{{- end -}} +{{- toYaml $envList | nindent 0 -}} +{{- end -}} + +{{- define "fluentd-image" -}} +"{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" +{{- end -}} diff --git a/charts/lm-logs/templates/configmap.yaml b/charts/lm-logs/templates/configmap.yaml new file mode 100644 index 0000000..a799f58 --- /dev/null +++ b/charts/lm-logs/templates/configmap.yaml @@ -0,0 +1,99 @@ +kind: ConfigMap +apiVersion: v1 +metadata: + name: {{ include "fluentd.fullname" . }} + labels: + {{- include "fluentd.labels" . | nindent 4 }} + annotations: + {{- include "fluentd.annotations" . | nindent 4 }} +data: + fluent.conf: | + @include kubernetes.conf + + + log_level "#{ENV['FLUENT_LOG_LEVEL'] || 'warn'}" + + + + @type record_transformer + enable_ruby + + message ${record["log"]} ${record["message"]} + timestamp ${record["time"]} + {{- if or .Values.kubernetes.cluster_name .Values.global.clusterName }} + {{ include "kubernetes.cluster_name" . | nindent 8 }} + {{- end}} + {{- if .Values.fluent.device_less_logs }} + resource.service.name ${record.dig("kubernetes","labels","app") != nil ? record.dig("kubernetes","labels","app") : record.dig("kubernetes","labels","app_kubernetes_io/name") != nil ? record.dig("kubernetes","labels","app_kubernetes_io/name") : record.dig("kubernetes","container_name") != nil ? record.dig("kubernetes","container_name") : record.dig("kubernetes","pod_name") != nil ? record.dig("kubernetes","pod_name") : "unknown" } + resource.service.namespace ${record["kubernetes"]["namespace_name"]} + {{- end}} + + remove_keys log + + + + @type lm + company_name {{ if .Values.lm_company_name }} {{ .Values.lm_company_name }} {{ else }} {{ required "A valid .Values.lm_company_name or .Values.global.account entry is required!" .Values.global.account }} {{ end }} + resource_mapping {"kubernetes.pod_name": "auto.name"} + access_id {{ .Values.lm_access_id | default .Values.global.accessID }} + access_key {{ .Values.lm_access_key | default .Values.global.accessKey }} + debug false + compression gzip + include_metadata {{ hasKey .Values.fluent "include_metadata" | ternary .Values.fluent.include_metadata true }} + device_less_logs {{ .Values.fluent.device_less_logs | default false }} + + @type memory + flush_interval {{ .Values.fluent.buffer.memory.flush_interval | default "1s" }} + chunk_limit_size {{ .Values.fluent.buffer.memory.chunk_limit_size | default "8m" }} + flush_thread_count {{ .Values.fluent.buffer.memory.flush_thread_count | default "8"}} + + + kubernetes.conf: | + + @type tail + @id in_tail_container_logs + path /var/log/containers/*.log + pos_file /var/log/fluentd-containers.log.pos + tag "#{ENV['FLUENT_CONTAINER_TAIL_TAG'] || 'kubernetes.*'}" + exclude_path "#{ENV['FLUENT_CONTAINER_TAIL_EXCLUDE_PATH'] || '/var/log/containers/{{ .Chart.Name }}*.log' }" + + @type "#{ENV['FLUENT_CONTAINER_TAIL_PARSER_TYPE'] || 'multi_format'}" + + format json + keep_time_key true + time_format %Y-%m-%dT%H:%M:%S.%NZ + + + format syslog + + + format none + + + + + + @type concat + key log + seperator "" + multiline_start_regexp {{ .Values.kubernetes.multiline_start_regexp }} + timeout_label @NORMAL + + + + + + @type kubernetes_metadata + @id filter_kube_metadata + kubernetes_url "#{ENV['FLUENT_FILTER_KUBERNETES_URL'] || 'https://' + ENV.fetch('KUBERNETES_SERVICE_HOST') + ':' + ENV.fetch('KUBERNETES_SERVICE_PORT') + '/api'}" + verify_ssl "#{ENV['KUBERNETES_VERIFY_SSL'] || true}" + ca_file "#{ENV['KUBERNETES_CA_FILE']}" + skip_labels "#{ENV['FLUENT_KUBERNETES_METADATA_SKIP_LABELS'] || 'false'}" + skip_container_metadata "#{ENV['FLUENT_KUBERNETES_METADATA_SKIP_CONTAINER_METADATA'] || 'false'}" + skip_master_url "#{ENV['FLUENT_KUBERNETES_METADATA_SKIP_MASTER_URL'] || 'false'}" + skip_namespace_metadata "#{ENV['FLUENT_KUBERNETES_METADATA_SKIP_NAMESPACE_METADATA'] || 'false'}" + diff --git a/charts/lm-logs/templates/deamonset.yaml b/charts/lm-logs/templates/deamonset.yaml new file mode 100644 index 0000000..bf62fc5 --- /dev/null +++ b/charts/lm-logs/templates/deamonset.yaml @@ -0,0 +1,53 @@ +apiVersion: apps/v1 +kind: DaemonSet +metadata: + name: {{ include "fluentd.fullname" . }} + labels: + {{- include "fluentd.labels" . | nindent 4 }} + annotations: + {{- include "fluentd.annotations" . | nindent 4 }} +spec: + selector: + matchLabels: + {{- include "fluentd.selectorLabels" . | nindent 6 }} + template: + metadata: + labels: + {{- include "fluentd.selectorLabels" . | nindent 8 }} + spec: + serviceAccountName: {{ include "fluentd.serviceAccountName" . }} + containers: + - name: {{ .Chart.Name }} + securityContext: + {{- toYaml .Values.securityContext | nindent 12 }} + image: {{ include "fluentd-image" . }} + env: + - name: K8S_NODE_NAME + valueFrom: + fieldRef: + fieldPath: spec.nodeName + {{ if gt (.Values.env | len) 0 }} + {{ include "ds-env" . | nindent 12 }} + {{ end }} + imagePullPolicy: {{ .Values.image.pullPolicy | default "Always" }} + resources: + {{- toYaml .Values.resources | nindent 12 }} + volumeMounts: + {{- toYaml .Values.volumeMounts | nindent 12 }} + volumes: + - name: fluentconf + configMap: + name: {{ include "fluentd.fullname" . }} + {{- toYaml .Values.volumes | nindent 8 }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} diff --git a/charts/lm-logs/templates/rbac.yaml b/charts/lm-logs/templates/rbac.yaml new file mode 100644 index 0000000..f462fda --- /dev/null +++ b/charts/lm-logs/templates/rbac.yaml @@ -0,0 +1,36 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "fluentd.serviceAccountName" . }} + labels: + {{- include "fluentd.labels" . | nindent 4 }} + +--- +apiVersion: {{ include "rbac.apiVersion" . }} +kind: ClusterRole +metadata: + name: {{ include "fluentd.serviceAccountName" . }} +rules: +- apiGroups: + - "" + resources: + - pods + - namespaces + verbs: + - get + - list + - watch + +--- +kind: ClusterRoleBinding +apiVersion: {{ include "rbac.apiVersion" . }} +metadata: + name: {{ include "fluentd.serviceAccountName" . }} +roleRef: + kind: ClusterRole + name: {{ include "fluentd.serviceAccountName" . }} + apiGroup: rbac.authorization.k8s.io +subjects: +- kind: ServiceAccount + name: {{ include "fluentd.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} \ No newline at end of file diff --git a/charts/lm-logs/values.schema.json b/charts/lm-logs/values.schema.json new file mode 100644 index 0000000..fde2606 --- /dev/null +++ b/charts/lm-logs/values.schema.json @@ -0,0 +1,502 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Lm-Logs Helm Chart Configuration Schema", + "type": "object", + "properties": { + "enabled": { + "$id": "#/properties/enabled", + "description": "Defined for umbrella chart but unused here.", + "type": "boolean", + "default": true, + "$comment": "tf:optional" + }, + "image": { + "additionalProperties": false, + "type": "object", + "properties": { + "repository": { + "$comment": "tf:optional", + "$id": "#/properties/image/properties/repository", + "type": "string", + "default": "logicmonitor/lm-logs-k8s-fluentd", + "examples": [ + "logicmonitor/lm-logs-k8s-fluentd" + ] + }, + "pullPolicy": { + "$id": "#/properties/image/properties/pullPolicy", + "$comment": "tf:optional", + "type": "string", + "description": "Overrides the image pullPolicy.\nDefaults to \"Always\".", + "default": "Always", + "enum": [ + "Always", + "IfNotPresent", + "Never", + "" + ], + "examples": [ + "Always" + ] + }, + "tag": { + "$id": "#/properties/image/properties/tag", + "$comment": "tf:optional", + "type": "string", + "description": "The \"logicmonitor/lm-logs-k8s-fluentd\" Docker Image Tag.\nOverrides the image tag whose default is the chart appVersion.", + "default": "", + "examples": [ + "" + ] + } + } + }, + "lm_access_id": { + "$id": "#/properties/lm_access_id", + "type": "string", + "title": "Logicmonitor API Token accessID", + "description": "The LogicMonitor API key ID.\nNOTE: Ensure to add surrounding double quotes to avoid special character parsing errors.", + "default": "", + "examples": [ + "" + ], + "$comment": "ui:lm_access_id-ignore tf:optional" + }, + "lm_access_key": { + "$id": "#/properties/lm_access_key", + "type": "string", + "title": "Logicmonitor API Token accessKey", + "description": "The LogicMonitor API key.\nNOTE: Ensure to add surrounding double quotes to avoid special character parsing errors.", + "default": "", + "examples": [ + "" + ], + "$comment": "ui:lm_access_key-ignore tf:optional" + }, + "lm_company_name": { + "$id": "#/properties/lm_company_name", + "type": "string", + "title": "Logicmonitor account name", + "description": "The LogicMonitor account name.nValue should be trimmed from URL \"___.logicmonitor.com\"\nexample: lmqauat.logicmonitor.com then \"lmqauat\" must be a valid value.", + "default": "", + "examples": [ + "lmqauat" + ], + "$comment": "ui:lm_company_name-ignore tf:optional" + }, + "clusterName": { + "$id": "#/properties/clusterName", + "type": "string", + "title": "Friendly Cluster Name", + "description": "The unique name to give to the cluster's resource group.\nNOTE: You must not change the name once the application is deployed in the cluster. If changed, breaks correlation at multiple places\nexample: Organised Resource group name of Kubernetes resource tree, is generated as \"Kubernetes Cluster: \"", + "default": "", + "examples": [ + "" + ], + "$comment": "ui:clusterName-ignore tf:" + }, + "global": { + "type": "object", + "additionalProperties": true, + "properties": { + "accessID": { + "$id": "#/properties/global/properties/accessID", + "type": "string", + "title": "Logicmonitor API Token accessID", + "description": "The LogicMonitor API key ID.\nNOTE: Ensure to add surrounding double quotes to avoid special character parsing errors.", + "default": "", + "examples": [ + "" + ], + "$comment": "ui:accessId-ignore tf:optional" + }, + "accessKey": { + "$id": "#/properties/global/properties/accessKey", + "type": "string", + "title": "Logicmonitor API Token accessKey", + "description": "The LogicMonitor API key.\nNOTE: Ensure to add surrounding double quotes to avoid special character parsing errors.", + "default": "", + "examples": [ + "" + ], + "$comment": "ui:accessKey-ignore tf:optional" + }, + "account": { + "$id": "#/properties/global/properties/account", + "type": "string", + "title": "Logicmonitor account name", + "description": "The LogicMonitor account name.nValue should be trimmed from URL \"___.logicmonitor.com\"\nexample: lmqauat.logicmonitor.com then \"lmqauat\" must be a valid value.", + "default": "", + "examples": [ + "lmqauat" + ], + "$comment": "ui:account-ignore tf:optional" + }, + "clusterName": { + "$id": "#/properties/clusterName", + "type": "string", + "title": "Friendly Cluster Name", + "description": "The unique name to give to the cluster's resource group.\nNOTE: You must not change the name once the application is deployed in the cluster. If changed, breaks correlation at multiple places\nexample: Organised Resource group name of Kubernetes resource tree, is generated as \"Kubernetes Cluster: \"", + "default": "", + "examples": [ + "" + ], + "$comment": "ui:clusterName-ignore tf:" + } + } + }, + "imagePullSecrets": { + "description": "ImagePullSecrets is an optional list of references to secrets in the same namespace to use for pulling any of the images used by this PodSpec. If specified, these secrets will be passed to individual puller implementations for them to use. For example, in the case of docker, only DockerConfig type secrets are honored. More info: https://kubernetes.io/docs/concepts/containers/images#specifying-imagepullsecrets-on-a-pod", + "examples": [ + [ + { + "name": "imagepullsecret1" + } + ] + ], + "items": { + "$ref": "#/definitions/io.k8s.api.core.v1.LocalObjectReference" + }, + "uniqueItems": true, + "additionalProperties": false, + "type": "array" + }, + "labels": { + "$id": "#/properties/labels", + "type": "object", + "$comment": "tf:optional,yamlencode", + "default": {}, + "examples": [ + {} + ], + "additionalProperties": { + "type": "string" + } + }, + "annotations": { + "$id": "#/properties/annotations", + "type": "object", + "default": {}, + "examples": [ + {} + ], + "additionalProperties": { + "type": "string" + }, + "$comment": "tf:optional,yamlencode" + }, + "nameOverride": { + "$id": "#/properties/nameOverride", + "$comment": "tf:optional", + "type": "string", + "title": "The nameOverride schema", + "default": "", + "examples": [ + "" + ] + }, + "fullnameOverride": { + "$comment": "tf:optional", + "$id": "#/properties/fullnameOverride", + "type": "string", + "title": "The fullnameOverride schema", + "default": "", + "examples": [ + "" + ] + }, + "env": { + "$id": "#/properties/env", + "type": "object", + "$comment": "tf:optional,yamlencode", + "default": {}, + "examples": [ + {} + ], + "additionalProperties": { + "type": "string" + } + }, + "resources": { + "$id": "#/properties/resources", + "type": "object", + "$comment": "tf:optional", + "title": "The Argus resource limits schema", + "description": "The Argus pod resource limits", + "default": {}, + "examples": [ + { + "limits": { + "cpu": "1000m", + "memory": "1Gi", + "ephemeral-storage": "100Mi" + }, + "requests": { + "cpu": "1000m", + "memory": "1Gi", + "ephemeral-storage": "100Mi" + } + } + ], + "properties": { + "limits": { + "$id": "#/properties/resources/properties/limits", + "$comment": "tf:optional,yamlencode", + "additionalProperties": { + "$ref": "#/definitions/io.k8s.apimachinery.pkg.api.resource.Quantity" + }, + "description": "Limits describes the maximum amount of compute resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/", + "type": "object" + }, + "requests": { + "$id": "#/properties/resources/properties/requests", + "$comment": "tf:optional,yamlencode", + "additionalProperties": { + "$ref": "#/definitions/io.k8s.apimachinery.pkg.api.resource.Quantity" + }, + "description": "Requests describes the minimum amount of compute resources required. If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, otherwise to an implementation-defined value. More info: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/", + "type": "object" + } + }, + "additionalProperties": false + }, + "fluent": { + "additionalProperties": false, + "type": "object", + "properties": { + "device_less_logs": { + "type": "boolean" + }, + "include_metadata": { + "type": "boolean" + }, + "buffer": { + "type": "object", + "additionalProperties": false, + "properties": { + "memory": { + "type": "object", + "additionalProperties": false, + "properties": { + "flush_interval": { + "type": "string" + }, + "chunk_limit_size": { + "type": "string" + }, + "flush_thread_count": { + "type": "integer" + } + } + } + } + } + } + }, + "kubernetes": { + "additionalProperties": false, + "type": "object", + "properties": { + "multiline_start_regexp": { + "type": "string" + }, + "cluster_name" : { + "type": "string" + } + } + }, + "nodeSelector": { + "$id": "#/properties/nodeSelector", + "$comment": "tf:optional,yamlencode", + "type": "object", + "title": "nodeSelector", + "description": "NodeSelector is a selector, which must be set to true for the pod to fit on a node. The selector must match the node's labels for the pod to be scheduled on that node. More info: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/", + "default": {}, + "examples": [ + {} + ], + "additionalProperties": { + "type": "string" + } + }, + "affinity": { + "$id": "#/properties/affinity", + "type": "object", + "$comment": "tf:optional,yamlencode", + "title": "affinity", + "description": "Affinity allows you to constrain which nodes your pod is eligible to be scheduled on.", + "default": {}, + "examples": [ + {} + ] + }, + "tolerations": { + "additionalItems": true, + "items": { + "$id": "#/properties/tolerations/items", + "$ref": "#/definitions/toleration" + }, + "uniqueItems": true, + "type": "array" + }, + "volumes": { + "type": "array", + "items": { + "$ref": "#/definitions/io.k8s.api.core.v1.Volume" + }, + "uniqueItems": true + }, + "volumeMounts": { + "type": "array", + "items": { + "$ref": "#/definitions/io.k8s.api.core.v1.VolumeMount" + }, + "uniqueItems": true + } + }, + "additionalProperties": false, + "required": [ + "lm_access_id", + "lm_access_key", + "lm_company_name" + ], + "definitions": { + "io.k8s.apimachinery.pkg.api.resource.Quantity": { + "oneOf": [ + { + "type": "string" + }, + { + "type": "number" + } + ] + }, + "io.k8s.api.core.v1.LocalObjectReference": { + "description": "LocalObjectReference contains information to locate the referenced object inside the same namespace.", + "properties": { + "name": { + "description": "Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names", + "type": "string" + } + }, + "type": "object" + }, + "io.k8s.api.core.v1.VolumeMount": { + "description": "VolumeMount describes a mounting of a Volume within a container.", + "required": [ + "name", + "mountPath" + ], + "properties": { + "mountPath": { + "description": "Path within the container at which the volume should be mounted. Must not contain ':'.", + "type": "string" + }, + "name": { + "description": "This must match the Name of a Volume.", + "type": "string" + }, + "readOnly": { + "description": "Mounted read-only if true, read-write otherwise (false or unspecified). Defaults to false.", + "type": "boolean" + }, + "subPath": { + "description": "Path within the volume from which the container's volume should be mounted. Defaults to \"\" (volume's root).", + "type": "string" + } + } + }, + "io.k8s.api.core.v1.Volume": { + "properties": { + "hostPath": { + "description": "Represents a host path mapped into a pod. Host path volumes do not support ownership management or SELinux relabeling.", + "properties": { + "path": { + "description": "Path of the directory on the host. If the path is a symlink, it will follow the link to the real path. More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath", + "type": "string" + }, + "type": { + "description": "Type for HostPath Volume, by default is set to \"\" More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath", + "type": "string" + } + }, + "required": [ + "path" + ], + "type": "object" + }, + "name": { + "description": "Volume's name. Must be a DNS_LABEL and unique within the pod. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names", + "type": "string" + } + }, + "required": [ + "name" + ] + }, + "toleration": { + "oneOf": [ + { + "properties": { + "effect": { + "description": "Effect indicates the taint effect to match. Empty means match all taint effects. When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute.", + "type": "string" + }, + "key": { + "description": "Key is the taint key that the toleration applies to. Empty means match all taint keys. If the key is empty, operator must be Exists; this combination means to match all values and all keys.", + "type": "string" + }, + "operator": { + "description": "Operator represents a key's relationship to the value. Valid operators are Exists and Equal. Defaults to Equal. Exists is equivalent to wildcard for value, so that a pod can tolerate all taints of a particular category.", + "type": "string", + "enum": [ + "Exists" + ] + }, + "tolerationSeconds": { + "description": "TolerationSeconds represents the period of time the toleration (which must be of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, it is not set, which means tolerate the taint forever (do not evict). Zero and negative values will be treated as 0 (evict immediately) by the system.", + "format": "int64", + "type": "integer" + }, + "value": { + "description": "Value is the taint value the toleration matches to. If the operator is Exists, the value should be empty, otherwise just a regular string.", + "type": "string", + "maxLength": 0 + } + }, + "type": "object" + }, + { + "properties": { + "effect": { + "description": "Effect indicates the taint effect to match. Empty means match all taint effects. When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute.", + "type": "string" + }, + "key": { + "description": "Key is the taint key that the toleration applies to. Empty means match all taint keys. If the key is empty, operator must be Exists; this combination means to match all values and all keys.", + "type": "string" + }, + "operator": { + "description": "Operator represents a key's relationship to the value. Valid operators are Exists and Equal. Defaults to Equal. Exists is equivalent to wildcard for value, so that a pod can tolerate all taints of a particular category.", + "type": "string", + "enum": [ + "Equal" + ] + }, + "tolerationSeconds": { + "description": "TolerationSeconds represents the period of time the toleration (which must be of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, it is not set, which means tolerate the taint forever (do not evict). Zero and negative values will be treated as 0 (evict immediately) by the system.", + "format": "int64", + "type": "integer" + }, + "value": { + "description": "Value is the taint value the toleration matches to. If the operator is Exists, the value should be empty, otherwise just a regular string.", + "type": "string", + "minLength": 1 + } + }, + "type": "object" + } + ] + } + } +} diff --git a/charts/lm-logs/values.yaml b/charts/lm-logs/values.yaml new file mode 100644 index 0000000..ae77abf --- /dev/null +++ b/charts/lm-logs/values.yaml @@ -0,0 +1,62 @@ +image: + repository: logicmonitor/lm-logs-k8s-fluentd + pullPolicy: Always + tag: "1.0.5" + +lm_access_id: "" +lm_access_key: "" +lm_company_name: "" + +global: + accessID: "" + accessKey: "" + account: "" + +imagePullSecrets: [] +nameOverride: "" +fullnameOverride: "" + +labels: {} +annotations: {} + +env: {} + +resources: + limits: + memory: 1000Mi + requests: + cpu: 300m + memory: 700Mi +fluent: + device_less_logs: false + include_metadata: true + buffer: + memory: + flush_interval: 1s + chunk_limit_size: 8m + flush_thread_count: 8 + +kubernetes: + multiline_start_regexp: /^\[(\d{4}-)?\d{2}-\d{2} \d{2}:\d{2}:\d{2}.\d{3}.*\]/ + +nodeSelector: {} +affinity: {} +tolerations: [] + + +volumes: + - name: varlog + hostPath: + path: /var/log + - name: varlibdockercontainers + hostPath: + path: /var/lib/docker/containers + +volumeMounts: + - name: fluentconf + mountPath: /fluentd/etc + - name: varlog + mountPath: /var/log + - name: varlibdockercontainers + mountPath: /var/lib/docker/containers + readOnly: true