├── hooks └── pre-commit ├── .github └── workflows │ └── auto-approve.yml ├── compile-agents-yaml.sh ├── README.md ├── metadata-agent.yaml ├── heapster.yaml ├── rbac-setup.yaml ├── logging-agent.yaml └── agents.yaml /hooks/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ./compile-agents-yaml.sh 4 | 5 | -------------------------------------------------------------------------------- /.github/workflows/auto-approve.yml: -------------------------------------------------------------------------------- 1 | # Automatically approve PRs created by our release robot account. 2 | name: Auto approve 3 | on: pull_request 4 | 5 | jobs: 6 | auto-approve: 7 | runs-on: ubuntu-latest 8 | steps: 9 | - uses: hmarr/auto-approve-action@v2.0.0 10 | if: github.actor == 'stackdriver-instrumentation-release' 11 | with: 12 | github-token: "${{ secrets.GITHUB_TOKEN }}" 13 | -------------------------------------------------------------------------------- /compile-agents-yaml.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -eu 2 | # 3 | # Copyright 2018 Google LLC 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | echo "# THIS FILE IS AUTO-GENERATED DO NOT EDIT" > agents.yaml 18 | 19 | GLOBIGNORE="rbac-setup.yaml:agents.yaml" 20 | for f in *.yaml; do 21 | cat $f 22 | echo -e "\n---" 23 | done >> agents.yaml 24 | 25 | echo "agents.yaml has been generated for you." 26 | 27 | git add agents.yaml 28 | 29 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Stackdriver Kubernetes Configs 2 | 3 | A collection of Kubernetes configurations to integrate with Stackdriver 4 | products. For now, it supports [Stackdriver Logging](https://cloud.google.com/logging/) 5 | and [Stackdriver Monitoring](https://cloud.google.com/monitoring/). This repo is only used 6 | for [manual installation](https://cloud.google.com/monitoring/kubernetes-engine/customizing) 7 | on existing clusters. 8 | 9 | ## Setting up git hooks 10 | 11 | From the root directory of this repo, please run the following command: 12 | 13 | ``` 14 | ln -s "$(realpath hooks/pre-commit)" "$(git rev-parse --git-dir)/hooks/pre-commit" 15 | ``` 16 | 17 | This will ensure that all commits run the 18 | [`compile-agents-yaml.sh`](#compile-agents-yaml) command. 19 | 20 | ## Compile Agents YAML 21 | 22 | From the root directory of this repo, you can run the following command: 23 | 24 | ``` 25 | ./compile-agents-yaml.sh 26 | ``` 27 | 28 | This will ensure that all commits re-generate the `agents.yaml` file to keep it 29 | up-to-date with other YAML file changes. 30 | 31 | -------------------------------------------------------------------------------- /metadata-agent.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | labels: 5 | app: stackdriver-metadata-agent 6 | cluster-level: "true" 7 | name: stackdriver-metadata-agent-cluster-level 8 | namespace: stackdriver-agents 9 | spec: 10 | replicas: 1 11 | selector: 12 | matchLabels: 13 | app: stackdriver-metadata-agent 14 | cluster-level: "true" 15 | template: 16 | metadata: 17 | labels: 18 | app: stackdriver-metadata-agent 19 | cluster-level: "true" 20 | spec: 21 | containers: 22 | - env: 23 | - name: CLUSTER_NAME 24 | valueFrom: 25 | configMapKeyRef: 26 | name: cluster-config 27 | key: cluster_name 28 | - name: CLUSTER_LOCATION 29 | valueFrom: 30 | configMapKeyRef: 31 | name: cluster-config 32 | key: cluster_location 33 | - name: GOOGLE_APPLICATION_CREDENTIALS 34 | valueFrom: 35 | configMapKeyRef: 36 | name: google-cloud-config 37 | key: credentials_path 38 | - name: PROMETHEUS_PORT 39 | value: "8888" 40 | args: 41 | - -logtostderr 42 | - -v=1 43 | image: gcr.io/stackdriver-agents/metadata-agent-go:1.3.0 44 | imagePullPolicy: IfNotPresent 45 | name: metadata-agent 46 | resources: 47 | requests: 48 | cpu: 40m 49 | memory: 50Mi 50 | ports: 51 | - name: metadata-agent 52 | containerPort: 8888 53 | terminationMessagePath: /dev/termination-log 54 | terminationMessagePolicy: File 55 | volumeMounts: 56 | - mountPath: /etc/google-cloud/ 57 | name: google-cloud-config 58 | - mountPath: /etc/ssl/certs 59 | name: ssl-certs 60 | dnsPolicy: ClusterFirst 61 | restartPolicy: Always 62 | schedulerName: default-scheduler 63 | securityContext: {} 64 | serviceAccount: metadata-agent 65 | serviceAccountName: metadata-agent 66 | tolerations: 67 | - operator: "Exists" 68 | effect: "NoExecute" 69 | - operator: "Exists" 70 | effect: "NoSchedule" 71 | terminationGracePeriodSeconds: 5 72 | volumes: 73 | - configMap: 74 | defaultMode: 420 75 | name: google-cloud-config 76 | name: google-cloud-config 77 | - hostPath: 78 | path: /etc/ssl/certs 79 | type: Directory 80 | name: ssl-certs 81 | strategy: 82 | rollingUpdate: 83 | maxUnavailable: 1 84 | type: RollingUpdate 85 | -------------------------------------------------------------------------------- /heapster.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | labels: 5 | k8s-app: stackdriver-heapster 6 | version: v1.6.1 7 | name: heapster 8 | namespace: stackdriver-agents 9 | spec: 10 | replicas: 1 11 | selector: 12 | matchLabels: 13 | k8s-app: stackdriver-heapster 14 | strategy: 15 | rollingUpdate: 16 | maxSurge: 1 17 | maxUnavailable: 1 18 | type: RollingUpdate 19 | template: 20 | metadata: 21 | creationTimestamp: null 22 | labels: 23 | k8s-app: stackdriver-heapster 24 | version: v1.6.1 25 | spec: 26 | containers: 27 | - env: 28 | - name: CLUSTER_NAME 29 | valueFrom: 30 | configMapKeyRef: 31 | name: cluster-config 32 | key: cluster_name 33 | - name: CLUSTER_LOCATION 34 | valueFrom: 35 | configMapKeyRef: 36 | name: cluster-config 37 | key: cluster_location 38 | - name: GOOGLE_APPLICATION_CREDENTIALS 39 | valueFrom: 40 | configMapKeyRef: 41 | name: google-cloud-config 42 | key: credentials_path 43 | command: 44 | - /heapster 45 | - --source=kubernetes.summary_api:https://kubernetes.default?kubeletHttps=true&kubeletPort=10250&insecure=true 46 | - --sink=stackdriver:?cluster_name=$(CLUSTER_NAME)&cluster_location=$(CLUSTER_LOCATION)&zone=$(CLUSTER_LOCATION)&use_old_resources=false&use_new_resources=true&min_interval_sec=100&batch_export_timeout_sec=110 47 | image: gcr.io/stackdriver-agents/heapster-amd64:v1.6.1 48 | imagePullPolicy: Always 49 | livenessProbe: 50 | failureThreshold: 3 51 | httpGet: 52 | path: /healthz 53 | port: 8082 54 | scheme: HTTP 55 | initialDelaySeconds: 180 56 | periodSeconds: 10 57 | successThreshold: 1 58 | timeoutSeconds: 5 59 | name: heapster 60 | resources: 61 | limits: 62 | cpu: 88m 63 | memory: 204Mi 64 | requests: 65 | cpu: 88m 66 | memory: 204Mi 67 | terminationMessagePath: /dev/termination-log 68 | terminationMessagePolicy: File 69 | volumeMounts: 70 | - mountPath: /etc/google-cloud/ 71 | name: google-cloud-config 72 | - command: 73 | - /pod_nanny 74 | - --cpu=80m 75 | - --extra-cpu=0.5m 76 | - --memory=140Mi 77 | - --extra-memory=4Mi 78 | - --threshold=5 79 | - --deployment=heapster 80 | - --container=heapster 81 | - --poll-period=300000 82 | - --estimator=exponential 83 | env: 84 | - name: MY_POD_NAME 85 | valueFrom: 86 | fieldRef: 87 | apiVersion: v1 88 | fieldPath: metadata.name 89 | - name: MY_POD_NAMESPACE 90 | valueFrom: 91 | fieldRef: 92 | apiVersion: v1 93 | fieldPath: metadata.namespace 94 | image: gcr.io/google_containers/addon-resizer:1.7 95 | imagePullPolicy: IfNotPresent 96 | name: heapster-nanny 97 | resources: 98 | limits: 99 | cpu: 50m 100 | memory: 112360Ki 101 | requests: 102 | cpu: 50m 103 | memory: 112360Ki 104 | terminationMessagePath: /dev/termination-log 105 | terminationMessagePolicy: File 106 | dnsPolicy: ClusterFirst 107 | restartPolicy: Always 108 | schedulerName: default-scheduler 109 | securityContext: {} 110 | serviceAccount: heapster 111 | serviceAccountName: heapster 112 | terminationGracePeriodSeconds: 30 113 | volumes: 114 | - configMap: 115 | defaultMode: 420 116 | name: google-cloud-config 117 | name: google-cloud-config 118 | -------------------------------------------------------------------------------- /rbac-setup.yaml: -------------------------------------------------------------------------------- 1 | # How to apply this YAML file: 2 | # $ kubectl apply -f rbac-setup.yaml --as=admin --as-group=system:masters 3 | # 4 | # Namespace for Stackdriver Agents related components. 5 | apiVersion: v1 6 | kind: Namespace 7 | metadata: 8 | name: stackdriver-agents 9 | --- 10 | # Config map for setting GOOGLE_APPLICATION_CREDENTIALS. 11 | apiVersion: v1 12 | data: 13 | credentials_path: "" 14 | kind: ConfigMap 15 | metadata: 16 | name: google-cloud-config 17 | namespace: stackdriver-agents 18 | --- 19 | # Config map for setting CLUSTER_NAME and CLUSTER_LOCATION env vars. 20 | apiVersion: v1 21 | data: 22 | cluster_name: "" 23 | cluster_location: "" 24 | kind: ConfigMap 25 | metadata: 26 | name: cluster-config 27 | namespace: stackdriver-agents 28 | --- 29 | # Service account for Metadata Agent. 30 | apiVersion: v1 31 | kind: ServiceAccount 32 | metadata: 33 | name: metadata-agent 34 | namespace: stackdriver-agents 35 | --- 36 | # ClusterRole with permissions required by Metadata Agent. 37 | apiVersion: rbac.authorization.k8s.io/v1 38 | kind: ClusterRole 39 | metadata: 40 | name: stackdriver-user:metadata-agent 41 | namespace: stackdriver-agents 42 | rules: 43 | - apiGroups: 44 | - '*' 45 | resources: 46 | - '*' 47 | verbs: 48 | - watch 49 | - get 50 | - list 51 | --- 52 | # ClusterRoleBinding for Metadata Agent. 53 | apiVersion: rbac.authorization.k8s.io/v1 54 | kind: ClusterRoleBinding 55 | metadata: 56 | name: stackdriver-user:metadata-agent 57 | namespace: stackdriver-agents 58 | roleRef: 59 | apiGroup: rbac.authorization.k8s.io 60 | kind: ClusterRole 61 | name: stackdriver-user:metadata-agent 62 | subjects: 63 | - kind: ServiceAccount 64 | name: metadata-agent 65 | namespace: stackdriver-agents 66 | --- 67 | # Service account for Logging Agent. 68 | apiVersion: v1 69 | kind: ServiceAccount 70 | metadata: 71 | name: logging-agent 72 | namespace: stackdriver-agents 73 | --- 74 | # ClusterRole with permissions required by Logging Agent 75 | # filter_kubernetes_metadata plugin. 76 | apiVersion: rbac.authorization.k8s.io/v1 77 | kind: ClusterRole 78 | metadata: 79 | name: stackdriver-user:logging-agent 80 | namespace: stackdriver-agents 81 | rules: 82 | - apiGroups: 83 | - "" 84 | resources: 85 | - pods 86 | - namespaces 87 | verbs: 88 | - watch 89 | - get 90 | - list 91 | --- 92 | # ClusterRoleBinding for Logging Agent. 93 | apiVersion: rbac.authorization.k8s.io/v1 94 | kind: ClusterRoleBinding 95 | metadata: 96 | name: stackdriver-user:logging-agent 97 | namespace: stackdriver-agents 98 | roleRef: 99 | apiGroup: rbac.authorization.k8s.io 100 | kind: ClusterRole 101 | name: stackdriver-user:logging-agent 102 | subjects: 103 | - kind: ServiceAccount 104 | name: logging-agent 105 | namespace: stackdriver-agents 106 | --- 107 | # Service account for Heapster. 108 | apiVersion: v1 109 | kind: ServiceAccount 110 | metadata: 111 | name: heapster 112 | namespace: stackdriver-agents 113 | --- 114 | # ClusterRole with permissions required by Heapster. 115 | apiVersion: rbac.authorization.k8s.io/v1 116 | kind: ClusterRole 117 | metadata: 118 | name: stackdriver-user:heapster 119 | namespace: stackdriver-agents 120 | rules: 121 | - apiGroups: 122 | - "" 123 | resources: 124 | - events 125 | - namespaces 126 | - nodes 127 | - nodes/stats 128 | - pods 129 | verbs: 130 | - get 131 | - list 132 | - watch 133 | - apiGroups: 134 | - extensions 135 | resources: 136 | - deployments 137 | verbs: 138 | - get 139 | - list 140 | - watch 141 | --- 142 | # ClusterRoleBinding for Heapster. 143 | apiVersion: rbac.authorization.k8s.io/v1 144 | kind: ClusterRoleBinding 145 | metadata: 146 | name: stackdriver-user:heapster 147 | namespace: stackdriver-agents 148 | roleRef: 149 | apiGroup: rbac.authorization.k8s.io 150 | kind: ClusterRole 151 | name: stackdriver-user:heapster 152 | subjects: 153 | - kind: ServiceAccount 154 | name: heapster 155 | namespace: stackdriver-agents 156 | -------------------------------------------------------------------------------- /logging-agent.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: DaemonSet 3 | metadata: 4 | labels: 5 | app: stackdriver-logging-agent 6 | name: stackdriver-logging-agent 7 | namespace: stackdriver-agents 8 | spec: 9 | selector: 10 | matchLabels: 11 | app: stackdriver-logging-agent 12 | template: 13 | metadata: 14 | labels: 15 | app: stackdriver-logging-agent 16 | spec: 17 | containers: 18 | - env: 19 | - name: NODE_NAME 20 | valueFrom: 21 | fieldRef: 22 | apiVersion: v1 23 | fieldPath: spec.nodeName 24 | - name: K8S_NODE_NAME 25 | valueFrom: 26 | fieldRef: 27 | apiVersion: v1 28 | fieldPath: spec.nodeName 29 | - name: GOOGLE_APPLICATION_CREDENTIALS 30 | valueFrom: 31 | configMapKeyRef: 32 | name: google-cloud-config 33 | key: credentials_path 34 | - name: CLUSTER_NAME 35 | valueFrom: 36 | configMapKeyRef: 37 | name: cluster-config 38 | key: cluster_name 39 | - name: CLUSTER_LOCATION 40 | valueFrom: 41 | configMapKeyRef: 42 | name: cluster-config 43 | key: cluster_location 44 | image: gcr.io/stackdriver-agents/stackdriver-logging-agent:1.10.3 45 | imagePullPolicy: IfNotPresent 46 | livenessProbe: 47 | exec: 48 | command: 49 | - /bin/sh 50 | - -c 51 | - | 52 | LIVENESS_THRESHOLD_SECONDS=${LIVENESS_THRESHOLD_SECONDS:-300}; STUCK_THRESHOLD_SECONDS=${LIVENESS_THRESHOLD_SECONDS:-900}; if [ ! -e /var/run/google-fluentd/buffers ]; then 53 | exit 1; 54 | fi; touch -d "${STUCK_THRESHOLD_SECONDS} seconds ago" /tmp/marker-stuck; if [[ -z "$(find /var/run/google-fluentd/buffers -type f -newer /tmp/marker-stuck -print -quit)" ]]; then 55 | rm -rf /var/run/google-fluentd/buffers; 56 | exit 1; 57 | fi; touch -d "${LIVENESS_THRESHOLD_SECONDS} seconds ago" /tmp/marker-liveness; if [[ -z "$(find /var/run/google-fluentd/buffers -type f -newer /tmp/marker-liveness -print -quit)" ]]; then 58 | exit 1; 59 | fi; 60 | failureThreshold: 3 61 | initialDelaySeconds: 600 62 | periodSeconds: 60 63 | successThreshold: 1 64 | timeoutSeconds: 1 65 | name: logging-agent 66 | resources: 67 | limits: 68 | cpu: "1" 69 | memory: 300Mi 70 | requests: 71 | cpu: 100m 72 | memory: 200Mi 73 | terminationMessagePath: /dev/termination-log 74 | terminationMessagePolicy: File 75 | volumeMounts: 76 | - mountPath: /var/run 77 | name: varrun 78 | - mountPath: /var/log 79 | name: varlog 80 | - mountPath: /var/lib/docker/containers 81 | name: varlibdockercontainers 82 | readOnly: true 83 | - mountPath: /etc/google-fluentd/google-fluentd.conf 84 | subPath: google-fluentd.conf 85 | name: output-config-volume 86 | - mountPath: /etc/google-fluentd/config.d 87 | name: input-config-volume 88 | - mountPath: /etc/google-cloud/ 89 | name: google-cloud-config 90 | serviceAccount: logging-agent 91 | serviceAccountName: logging-agent 92 | dnsPolicy: ClusterFirst 93 | restartPolicy: Always 94 | schedulerName: default-scheduler 95 | securityContext: {} 96 | tolerations: 97 | - operator: "Exists" 98 | effect: "NoExecute" 99 | - operator: "Exists" 100 | effect: "NoSchedule" 101 | volumes: 102 | - hostPath: 103 | path: /var/run 104 | type: "" 105 | name: varrun 106 | - hostPath: 107 | path: /var/log 108 | type: "" 109 | name: varlog 110 | - hostPath: 111 | path: /var/lib/docker/containers 112 | type: "" 113 | name: varlibdockercontainers 114 | - configMap: 115 | defaultMode: 420 116 | name: logging-agent-output-config 117 | name: output-config-volume 118 | - configMap: 119 | defaultMode: 420 120 | name: logging-agent-input-config 121 | name: input-config-volume 122 | - configMap: 123 | defaultMode: 420 124 | name: google-cloud-config 125 | name: google-cloud-config 126 | updateStrategy: 127 | rollingUpdate: 128 | maxUnavailable: 1 129 | type: RollingUpdate 130 | --- 131 | # Config map for Logging Agent input and corresponding filter plugins. 132 | apiVersion: v1 133 | kind: ConfigMap 134 | metadata: 135 | name: logging-agent-input-config 136 | namespace: stackdriver-agents 137 | data: 138 | 1.containers.input.conf: |- 139 | # This configuration file for Fluentd is used 140 | # to watch changes to Docker log files that live in the 141 | # directory /var/lib/docker/containers/ and are symbolically 142 | # linked to from the /var/log/containers directory using names that capture the 143 | # pod name and container name. These logs are then submitted to 144 | # Google Cloud Logging which assumes the installation of the cloud-logging plug-in. 145 | # 146 | # Example 147 | # ======= 148 | # A line in the Docker log file might look like this JSON: 149 | # 150 | # {"log":"2014/09/25 21:15:03 Got request with path wombat\\n", 151 | # "stream":"stderr", 152 | # "time":"2014-09-25T21:15:03.499185026Z"} 153 | # 154 | # The original tag is derived from the log file's location. 155 | # For example a Docker container's logs might be in the directory: 156 | # /var/lib/docker/containers/997599971ee6366d4a5920d25b79286ad45ff37a74494f262e3bc98d909d0a7b 157 | # and in the file: 158 | # 997599971ee6366d4a5920d25b79286ad45ff37a74494f262e3bc98d909d0a7b-json.log 159 | # where 997599971ee6... is the Docker ID of the running container. 160 | # The Kubernetes kubelet makes a symbolic link to this file on the host 161 | # machine in the /var/log/containers directory which includes the pod name, 162 | # the namespace name and the Kubernetes container name: 163 | # synthetic-logger-0.25lps-pod_default_synth-lgr-997599971ee6366d4a5920d25b79286ad45ff37a74494f262e3bc98d909d0a7b.log 164 | # -> 165 | # /var/lib/docker/containers/997599971ee6366d4a5920d25b79286ad45ff37a74494f262e3bc98d909d0a7b/997599971ee6366d4a5920d25b79286ad45ff37a74494f262e3bc98d909d0a7b-json.log 166 | # The /var/log directory on the host is mapped to the /var/log directory in the container 167 | # running this instance of Fluentd and we end up collecting the file: 168 | # /var/log/containers/synthetic-logger-0.25lps-pod_default_synth-lgr-997599971ee6366d4a5920d25b79286ad45ff37a74494f262e3bc98d909d0a7b.log 169 | # This results in the tag: 170 | # var.log.containers.synthetic-logger-0.25lps-pod_default_synth-lgr-997599971ee6366d4a5920d25b79286ad45ff37a74494f262e3bc98d909d0a7b.log 171 | # where 'synthetic-logger-0.25lps-pod' is the pod name, 'default' is the 172 | # namespace name, 'synth-lgr' is the container name and '997599971ee6..' is 173 | # the container ID. 174 | # The record reformer is used to extract pod_name, namespace_name and 175 | # container_name from the tag and set them in a local_resource_id in the 176 | # format of: 177 | # 'k8s_container...'. 178 | # The reformer also changes the tags to 'stderr' or 'stdout' based on the 179 | # value of 'stream'. 180 | # local_resource_id is later used by google_cloud plugin to determine the 181 | # monitored resource to ingest logs against. 182 | 183 | # Json Log Example: 184 | # {"log":"[info:2016-02-16T16:04:05.930-08:00] Some log text here\n","stream":"stdout","time":"2016-02-17T00:04:05.931087621Z"} 185 | # CRI Log Example: 186 | # 2016-02-17T00:04:05.931087621Z stdout F [info:2016-02-16T16:04:05.930-08:00] Some log text here 187 | 188 | @type tail 189 | path /var/log/containers/*.log 190 | pos_file /var/run/google-fluentd/pos-files/gcp-containers.pos 191 | # Tags at this point are in the format of: 192 | # reform.var.log.containers.__-.log 193 | tag reform.* 194 | read_from_head true 195 | 196 | @type multi_format 197 | 198 | format json 199 | time_key time 200 | time_format %Y-%m-%dT%H:%M:%S.%NZ 201 | 202 | 203 | format /^(? 206 | 207 | 208 | 209 | 210 | @type parser 211 | format /^(?\w)(? 217 | 218 | 219 | # This plugin uses environment variables KUBERNETES_SERVICE_HOST and 220 | # KUBERNETES_SERVICE_PORT to talk to the API server. These environment 221 | # variables are added by kubelet automatically. 222 | @type kubernetes_metadata 223 | # Interval in seconds to dump cache stats locally in the Fluentd log. 224 | stats_interval 300 225 | # TTL in seconds of each cached element. 226 | cache_ttl 30 227 | # Skip fetching unused metadata. 228 | skip_container_metadata true 229 | skip_master_url true 230 | skip_namespace_metadata true 231 | 232 | 233 | 234 | # We have to use record_modifier because only this plugin supports complex 235 | # logic to modify record the way we need. 236 | @type record_modifier 237 | enable_ruby true 238 | 239 | # Extract "kubernetes"->"labels" and set them as 240 | # "logging.googleapis.com/labels". Prefix these labels with 241 | # "k8s-pod" to distinguish with other labels and avoid 242 | # label name collision with other types of labels. 243 | _dummy_ ${if record.is_a?(Hash) && record.has_key?('kubernetes') && record['kubernetes'].has_key?('labels') && record['kubernetes']['labels'].is_a?(Hash); then; record["logging.googleapis.com/labels"] = record['kubernetes']['labels'].map{ |k, v| ["k8s-pod/#{k}", v]}.to_h; end; nil} 244 | 245 | # Delete this dummy field and the rest of "kubernetes" and "docker". 246 | remove_keys _dummy_,kubernetes,docker 247 | 248 | 249 | 250 | @type record_reformer 251 | enable_ruby true 252 | 253 | # Extract local_resource_id from tag for 'k8s_container' monitored 254 | # resource. The format is: 255 | # 'k8s_container...'. 256 | "logging.googleapis.com/local_resource_id" ${"k8s_container.#{tag_suffix[4].rpartition('.')[0].split('_')[1]}.#{tag_suffix[4].rpartition('.')[0].split('_')[0]}.#{tag_suffix[4].rpartition('.')[0].split('_')[2].rpartition('-')[0]}"} 257 | # Rename the field 'log' to a more generic field 'message'. This way the 258 | # fluent-plugin-google-cloud knows to flatten the field as textPayload 259 | # instead of jsonPayload after extracting 'time', 'severity' and 260 | # 'stream' from the record. 261 | message ${record['log']} 262 | # If 'severity' is not set, assume stderr is ERROR and stdout is INFO. 263 | severity ${record['severity'] || if record['stream'] == 'stderr' then 'ERROR' else 'INFO' end} 264 | 265 | tag ${if record['stream'] == 'stderr' then 'raw.stderr' else 'raw.stdout' end} 266 | remove_keys stream,log 267 | 268 | 269 | # Detect exceptions in the log output and forward them as one log entry. 270 | 271 | @type detect_exceptions 272 | 273 | remove_tag_prefix raw 274 | message message 275 | stream "logging.googleapis.com/local_resource_id" 276 | multiline_flush_interval 5 277 | max_bytes 500000 278 | max_lines 1000 279 | 280 | 2.pods.input.conf: |- 281 | # This configuration file for Fluentd is used 282 | # to watch changes to Kubernetes pod log files live in the 283 | # directory /var/log/pods/NAMESPACE_NAME_UID. The file name 284 | # is used to capture the pod namespace, name and uid. These 285 | # logs are then submitted to Google Cloud Logging with a 286 | # local_resource_id 'k8s_pod..' 287 | # which assumes the installation of the cloud-logging plug-in. 288 | 289 | @type tail 290 | path /var/log/pods/*/*.log 291 | pos_file /var/run/google-fluentd/pos-files/gcp-pods.pos 292 | # Tags at this point are in the format of: 293 | # pods.reform.var.log.pods.__..log 294 | tag pods.reform.* 295 | read_from_head true 296 | 297 | @type none 298 | 299 | 300 | 301 | @type record_reformer 302 | enable_ruby true 303 | 304 | # Extract local_resource_id from tag for 'k8s_pod' monitored 305 | # resource. The format is: 306 | # 'k8s_pod..'. 307 | "logging.googleapis.com/local_resource_id" ${"k8s_pod.#{tag_suffix[5].rpartition('.')[0].split('_')[0]}.#{tag_suffix[5].rpartition('.')[0].split('_')[1]}"} 308 | 309 | # Use the log file name as the tag. Currently only `gvisor` log is supported. 310 | tag ${"#{tag_suffix[5].rpartition('.')[0].rpartition('.')[2]}"} 311 | 312 | 7.system.input.conf: |- 313 | # Example: 314 | # Dec 21 23:17:22 gke-foo-1-1-4b5cbd14-node-4eoj startupscript: Finished running startup script /var/run/google.startup.script 315 | 316 | @type tail 317 | format syslog 318 | path /var/log/startupscript.log 319 | pos_file /var/run/google-fluentd/pos-files/gcp-startupscript.pos 320 | tag startupscript 321 | 322 | 323 | # Example: 324 | # I1118 21:26:53.975789 6 proxier.go:1096] Port "nodePort for kube-system/default-http-backend:http" (:31429/tcp) was open before and is still needed 325 | 326 | @type tail 327 | format multiline 328 | multiline_flush_interval 5s 329 | format_firstline /^\w\d{4}/ 330 | format1 /^(?\w)(?