diff --git a/CHANGELOG.md b/CHANGELOG.md index e389533dc..2ebea0b3e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,11 +6,17 @@ ### Changed - +- Nexus storage change ([#1341](https://github.com/opendevstack/ods-core/issues/1341)) +- Update Aqua cli to 760 ([#1344](https://github.com/opendevstack/ods-core/pull/1344)) ### Fixed +## [4.9.0] - 2025-8-06 + +- Security improvements ([#1328](https://github.com/opendevstack/ods-core/pull/1328)) +- Added Helm Opentelemetry Collector Infrastructure configuration (([#1339](https://github.com/opendevstack/ods-core/issues/1339)) + ## [4.8.0] - 2025-4-10 ### Added diff --git a/Makefile b/Makefile index 041526496..7e973de64 100644 --- a/Makefile +++ b/Makefile @@ -163,6 +163,22 @@ configure-nexus: ### configure-nexus is not part of install-nexus because it is not idempotent yet. +# OPENTELEMETRY COLLECTOR +## Install or update Opentelemetry Collector. +install-opentelemetry-collector: apply-opentelemetry-collector-chart start-opentelemetry-collector-build +.PHONY: opentelemetry-collector + +## Apply OpenShift resources related to the Opentelemetry Collector. +apply-opentelemetry-collector-chart: + cd opentelemetry-collector/chart && envsubst < values.yaml.template > values.yaml && helm upgrade --install --namespace $(ODS_NAMESPACE) opentelemetry-collector . && rm values.yaml +.PHONY: apply-opentelemetry-collector-chart + +## Start build of BuildConfig "Opentelemetry Collector". +start-opentelemetry-collector-build: + ocp-scripts/start-and-follow-build.sh --namespace $(ODS_NAMESPACE) --build-config opentelemetry-collector +.PHONY: start-opentelemetry-collector-build + + # BACKUP ## Create a backup of the current state. backup: backup-sonarqube backup-ocp-config diff --git a/configuration-sample/ods-core.env.sample b/configuration-sample/ods-core.env.sample index b913cc19a..b041f0f93 100644 --- a/configuration-sample/ods-core.env.sample +++ b/configuration-sample/ods-core.env.sample @@ -409,3 +409,31 @@ AQUA_ALERT_EMAILS= # The name of a Nexus repository to store the reports generated by Aqua AQUA_NEXUS_REPOSITORY=leva-documentation + +########################## +# Opentelemety Collector # +########################## +# The docker image used to build the Opentelemetry Collector +OPENTELEMETRY_COLLECTOR_IMAGE=otel/opentelemetry-collector-k8s + +# The docker image tag used to build the Opentelemetry Collector +OPENTELEMETRY_COLLECTOR_IMAGE_TAG=0.123.0-amd64 + +# The Go memory limit for the Opentelemetry Collector +OPENTELEMETRY_COLLECTOR_GOMEMLIMIT=128MiB + +# The endpoint to send telemetry data using the OpenTelemetry Protocol (OTLP) +OPENTELEMETRY_COLLECTOR_OTLP_API_ENDPOINT=https://fake-jaeger/v1/traces + +# The Authorization Token used to authenticate requests sent to the OTLP_API_ENDPOINT +OPENTELEMETRY_COLLECTOR_OTLP_API_TOKEN=Api-Token fakeJaegerIDToken + +# The Host of the Opentelemetry Collector +OPENTELEMETRY_COLLECTOR_INGRESS_HOST=fake.opentelemetry-collector.com + +# Resource requests and limits for the Opentelemetry Collector +OPENTELEMETRY_COLLECTOR_CPU_REQUEST=200m +OPENTELEMETRY_COLLECTOR_MEMORY_REQUEST=128Mi +OPENTELEMETRY_COLLECTOR_CPU_LIMIT=1 +OPENTELEMETRY_COLLECTOR_MEMORY_LIMIT=256Mi + diff --git a/create-projects/Jenkinsfile b/create-projects/Jenkinsfile index 4778b7618..20daa4d47 100644 --- a/create-projects/Jenkinsfile +++ b/create-projects/Jenkinsfile @@ -80,7 +80,6 @@ podTemplate( sh( script: """./create-projects/create-projects.sh --verbose \ --project=${projectId} \ - --admins=${projectAdmins} \ --groups=${projectGroups}""", label: 'Create OpenShift projects' ) diff --git a/create-projects/create-projects.sh b/create-projects/create-projects.sh index 37a5c3752..237a3d3e8 100755 --- a/create-projects/create-projects.sh +++ b/create-projects/create-projects.sh @@ -84,14 +84,16 @@ fi if [ -n "${PROJECT_GROUPS}" ]; then echo "Seeding special permission groups (${PROJECT_GROUPS}) ..." + + cd_usergroup_role="edit-atlassian-team" + usergroup_role="edit" + admingroup_role="admin" + readonlygroup_role="view" + for group in ${PROJECT_GROUPS//,/ }; do groupName=$(echo "${group}" | cut -d "=" -f1) groupValue=$(echo "${group}" | cut -d "=" -f2) - usergroup_role="edit" - admingroup_role="admin" - readonlygroup_role="view" - if [ "${groupValue}" == "" ]; then continue fi @@ -101,7 +103,7 @@ if [ -n "${PROJECT_GROUPS}" ]; then if [[ "${groupName}" == *USERGROUP* ]]; then oc policy add-role-to-group "${usergroup_role}" "${groupValue}" -n "${PROJECT_ID}-dev" oc policy add-role-to-group "${usergroup_role}" "${groupValue}" -n "${PROJECT_ID}-test" - oc policy add-role-to-group "${usergroup_role}" "${groupValue}" -n "${PROJECT_ID}-cd" + oc policy add-role-to-group "${cd_usergroup_role}" "${groupValue}" -n "${PROJECT_ID}-cd" elif [[ "${groupName}" == *ADMINGROUP* ]]; then oc policy add-role-to-group "${admingroup_role}" "${groupValue}" -n "${PROJECT_ID}-dev" oc policy add-role-to-group "${admingroup_role}" "${groupValue}" -n "${PROJECT_ID}-test" diff --git a/create-projects/tests/run.sh b/create-projects/tests/run.sh index 0236f2509..0a6a06546 100755 --- a/create-projects/tests/run.sh +++ b/create-projects/tests/run.sh @@ -52,20 +52,16 @@ oc mock --receive 'policy add-role-to-group view system:authenticated -n foo-cd' oc mock --verify echo "" -echo "=== create-projects: With admins but no groups ===" +echo "=== create-projects: Without admins and no groups ===" oc mock --receive='new-project' --times 3 -# Expect admins -oc mock --receive 'policy add-role-to-user admin foo.bar@example.com -n foo-cd' --times 1 -oc mock --receive 'policy add-role-to-user admin baz.qux@example.com -n foo-cd' --times 1 - # Expect default view/edit setup oc mock --receive 'policy add-role-to-group view system:authenticated -n foo-dev' --times 1 oc mock --receive 'policy add-role-to-group view system:authenticated -n foo-test' --times 1 oc mock --receive 'policy add-role-to-group view system:authenticated -n foo-cd' --times 1 -../create-projects.sh --project foo --admins foo.bar@example.com,baz.qux@example.com --groups= +../create-projects.sh --project foo --groups= oc mock --verify @@ -81,7 +77,7 @@ oc mock --receive 'policy add-role-to-group view baz -n foo-cd' --times 1 oc mock --receive 'policy add-role-to-group edit foo -n foo-dev' --times 1 oc mock --receive 'policy add-role-to-group edit foo -n foo-test' --times 1 -oc mock --receive 'policy add-role-to-group edit foo -n foo-cd' --times 1 +oc mock --receive 'policy add-role-to-group edit-atlassian-team foo -n foo-cd' --times 1 oc mock --receive 'policy add-role-to-group admin bar -n foo-dev' --times 1 oc mock --receive 'policy add-role-to-group admin bar -n foo-test' --times 1 diff --git a/jenkins/ocp-config/deploy/jenkins-master.yml b/jenkins/ocp-config/deploy/jenkins-master.yml index 4cfa0aa8a..79e816dc1 100644 --- a/jenkins/ocp-config/deploy/jenkins-master.yml +++ b/jenkins/ocp-config/deploy/jenkins-master.yml @@ -267,18 +267,6 @@ objects: name: '${JENKINS_SERVICE_NAME}' labels: template: ods-jenkins-template -- apiVersion: authorization.openshift.io/v1 - kind: RoleBinding - metadata: - name: '${JENKINS_SERVICE_NAME}_edit' - labels: - template: ods-jenkins-template - roleRef: - name: edit - subjects: - - kind: ServiceAccount - name: '${JENKINS_SERVICE_NAME}' - namespace: '${TAILOR_NAMESPACE}' - apiVersion: v1 kind: Service metadata: diff --git a/ods-setup/setup-ods-project.sh b/ods-setup/setup-ods-project.sh index 409e342e2..b27429fcd 100755 --- a/ods-setup/setup-ods-project.sh +++ b/ods-setup/setup-ods-project.sh @@ -69,6 +69,141 @@ if ! oc adm policy add-cluster-role-to-user self-provisioner system:serviceaccou exit 1 fi +# Create a new role 'edit-atlassian-team' without secret-related resources access +if ! oc get clusterrole edit-atlassian-team > /dev/null 2>&1; then + echo "You might not have enough rights to create the new role 'edit-atlassian-team'." + echo "This script needs to be run by a cluster admin." + + # Create a temporary file + TEMP_FILE=$(mktemp 2>/dev/null || echo "/tmp/tempfile_$$") + + # Get the edit role YAML and rename it + oc get clusterrole edit -o yaml | sed 's/name: edit/name: edit-atlassian-team/' > $TEMP_FILE + + # Process the YAML to remove secret-related resources, empty sections, and metadata fields + PROCESSED_FILE=$(mktemp 2>/dev/null || echo "/tmp/tempfile_$$") + + awk ' + BEGIN { + skip_current_group = 0; + inside_api_group = 0; + api_group_buffer = ""; + skip_section = 0; + in_metadata = 0; + contains_secret = 0; + } + + # Skip metadata fields and sections + /creationTimestamp:/ || /resourceVersion:/ || /uid:/ { + next; + } + + # Detect start of aggregationRule section and skip it + /^aggregationRule:/ { + skip_section = 1; + next; + } + + # Detect end of aggregationRule section (when we see apiVersion) + /^apiVersion:/ { + skip_section = 0; + print $0; + next; + } + + # Track if we are in metadata section + /^metadata:/ { + in_metadata = 1; + print $0; + next; + } + + # Detect start of annotations or labels in metadata and skip them + /^ annotations:/ || /^ labels:/ { + if (in_metadata) { + skip_section = 1; + next; + } + } + + # Detect when we leave annotations or labels section (any line with single indent level) + /^ [a-zA-Z]/ { + if (skip_section && in_metadata && $0 !~ /^ annotations:/ && $0 !~ /^ labels:/) { + skip_section = 0; + } + } + + # Detect end of metadata section + /^[a-zA-Z]/ && in_metadata && $0 !~ /^metadata:/ { + in_metadata = 0; + } + + # Skip lines while in a section we want to skip + { + if (skip_section) { + next; + } + } + + # Detect API Groups line + /^- apiGroups:/ { + # If we were previously in an API group, print it if it wasnt being skipped and has no secrets + if (inside_api_group && !skip_current_group && !contains_secret && api_group_buffer != "") { + print api_group_buffer; + } + + # Reset variables for new group + inside_api_group = 1; + api_group_buffer = $0; + skip_current_group = 0; + contains_secret = 0; + + # Check if this apiGroup itself contains "secret" + if ($0 ~ /secret/ || $0 ~ /external-secrets\.io/) { + skip_current_group = 1; + } + next; + } + + # Look for resources section that might contain secrets + /^ resources:/ { + api_group_buffer = api_group_buffer "\n" $0; + next; + } + + # Check for secret in resource names + /^ - / && inside_api_group { + # If this resource contains "secret", mark the group for skipping + if ($0 ~ /secret/) { + contains_secret = 1; + } + api_group_buffer = api_group_buffer "\n" $0; + next; + } + + # Process all other lines + { + if (inside_api_group) { + # Add to buffer + api_group_buffer = api_group_buffer "\n" $0; + } else { + # Not in an API group, print directly + print $0; + } + } + + END { + # Print the last API group if it wasnt being skipped and has no secrets + if (inside_api_group && !skip_current_group && !contains_secret && api_group_buffer != "") { + print api_group_buffer; + } + }' $TEMP_FILE > $PROCESSED_FILE + + # Create the role and clean up + oc create -f $PROCESSED_FILE + rm $TEMP_FILE $PROCESSED_FILE +fi + # Create cd-user secret cd ${SCRIPT_DIR}/ocp-config/cd-user ${TAILOR} -n ${NAMESPACE} apply ${NON_INTERACTIVE} ${REVEAL_SECRETS} diff --git a/opentelemetry-collector/.helmignore b/opentelemetry-collector/.helmignore new file mode 100644 index 000000000..0e8a0eb36 --- /dev/null +++ b/opentelemetry-collector/.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/opentelemetry-collector/README.md b/opentelemetry-collector/README.md new file mode 100644 index 000000000..4769de955 --- /dev/null +++ b/opentelemetry-collector/README.md @@ -0,0 +1,22 @@ +# Opentelemetry Collector + +The OpenTelemetry Collector is a vendor-agnostic way to receive, process, and export telemetry data. It supports various data formats and protocols, making it easy to collect and distribute your observability data. + +## Setup + +The OpenShift templates are located in the chart directory and can be compared with the OC cluster using Helm. For example, run cd chart && helm secrets diff upgrade to see if there is any drift between the current and desired state. + +To install the OpenTelemetry Collector, run: + +`helm install opentelemetry-collector .` + +## Configuration + +All the relevant configuration of the Opentelemetry Collector is store in the config map named collector-config in the same namespace where is running the pod. + +## Building a new image + +Push to this repository, then go to the build config in OC and start a new build. + +Aditionally you can run `make start-opentelemetry-collector-build`. + diff --git a/opentelemetry-collector/chart/Chart.yaml b/opentelemetry-collector/chart/Chart.yaml new file mode 100644 index 000000000..441d169ef --- /dev/null +++ b/opentelemetry-collector/chart/Chart.yaml @@ -0,0 +1,25 @@ +apiVersion: v2 +name: opentelemetry-collector +description: A Helm chart for Kubernetes that defines a Opentelemetry Collector +icon: https://opentelemetry.io/img/logos/opentelemetry-horizontal-color.svg + +# A chart can be either an 'application' or a 'library' chart. +# +# Application charts are a collection of templates that can be packaged into versioned archives +# to be deployed. +# +# Library charts provide useful utilities or functions for the chart developer. They're included as +# a dependency of application charts to inject those utilities and functions into the rendering +# pipeline. Library charts do not define any templates and therefore cannot be deployed. +type: application + +# This is the chart version. This version number should be incremented each time you make changes +# to the chart and its templates, including the app version. +# Versions are expected to follow Semantic Versioning (https://semver.org/) +version: 0.1.0 + +# This is the version number of the application being deployed. This version number should be +# incremented each time you make changes to the application. Versions are not expected to +# follow Semantic Versioning. They should reflect the version the application is using. +# It is recommended to use it with quotes. +appVersion: "0.123.0-amd64" diff --git a/opentelemetry-collector/chart/templates/NOTES.txt b/opentelemetry-collector/chart/templates/NOTES.txt new file mode 100644 index 000000000..7911e3a44 --- /dev/null +++ b/opentelemetry-collector/chart/templates/NOTES.txt @@ -0,0 +1,22 @@ +1. Get the application URL by running these commands: +{{- if .Values.ingress.enabled }} +{{- range $host := .Values.ingress.hosts }} + {{- range .paths }} + http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ .path }} + {{- end }} +{{- end }} +{{- else if contains "NodePort" .Values.service.type }} + export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "opentelemetry-collector.fullname" . }}) + export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") + echo http://$NODE_IP:$NODE_PORT +{{- else if contains "LoadBalancer" .Values.service.type }} + NOTE: It may take a few minutes for the LoadBalancer IP to be available. + You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "opentelemetry-collector.fullname" . }}' + export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "opentelemetry-collector.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}") + echo http://$SERVICE_IP:{{ .Values.service.port }} +{{- else if contains "ClusterIP" .Values.service.type }} + export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "opentelemetry-collector.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") + export CONTAINER_PORT=$(kubectl get pod --namespace {{ .Release.Namespace }} $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}") + echo "Visit http://127.0.0.1:8080 to use your application" + kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:$CONTAINER_PORT +{{- end }} diff --git a/opentelemetry-collector/chart/templates/_helpers.tpl b/opentelemetry-collector/chart/templates/_helpers.tpl new file mode 100644 index 000000000..96dcdc5af --- /dev/null +++ b/opentelemetry-collector/chart/templates/_helpers.tpl @@ -0,0 +1,62 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "opentelemetry-collector.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 "opentelemetry-collector.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 }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "opentelemetry-collector.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "opentelemetry-collector.labels" -}} +helm.sh/chart: {{ include "opentelemetry-collector.chart" . }} +{{ include "opentelemetry-collector.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "opentelemetry-collector.selectorLabels" -}} +app.kubernetes.io/name: {{ include "opentelemetry-collector.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "opentelemetry-collector.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "opentelemetry-collector.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} diff --git a/opentelemetry-collector/chart/templates/buildconfig.yaml b/opentelemetry-collector/chart/templates/buildconfig.yaml new file mode 100644 index 000000000..9feac13b2 --- /dev/null +++ b/opentelemetry-collector/chart/templates/buildconfig.yaml @@ -0,0 +1,39 @@ +apiVersion: build.openshift.io/v1 +kind: BuildConfig +metadata: + labels: + app: {{ .Values.collector.name }} + name: {{ .Values.collector.name }} +spec: + failedBuildsHistoryLimit: 5 + nodeSelector: null + output: + to: + kind: ImageStreamTag + name: {{ printf "%s:%s" .Values.collector.name .Values.global.odsImageTag }} + postCommit: {} + resources: + limits: + cpu: {{ .Values.buildConfig.cpuLimit }} + memory: {{ .Values.buildConfig.memLimit }} + requests: + cpu: {{ .Values.buildConfig.cpuRequest }} + memory: {{ .Values.buildConfig.memRequest }} + runPolicy: Serial + source: + contextDir: opentelemetry-collector/docker + git: + uri: {{ .Values.global.repoBase }}/{{ .Values.global.odsBitBucketProject }}/ods-core.git + ref: {{ .Values.global.odsGitRef }} + sourceSecret: + name: cd-user-token + type: Git + strategy: + type: Docker + dockerStrategy: + from: + kind: DockerImage + name: {{ .Values.collector.image }}:{{ .Values.collector.imageTag }} + forcePull: true + noCache: true + successfulBuildsHistoryLimit: 5 diff --git a/opentelemetry-collector/chart/templates/configmap.yaml b/opentelemetry-collector/chart/templates/configmap.yaml new file mode 100644 index 000000000..17a92dfdc --- /dev/null +++ b/opentelemetry-collector/chart/templates/configmap.yaml @@ -0,0 +1,48 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: collector-config +data: + otel-collector-config.yaml: | + receivers: + otlp: + protocols: + grpc: + endpoint: 0.0.0.0:4317 + http: + endpoint: 0.0.0.0:4318 + exporters: + otlphttp: + endpoint: ${OTLP_API_ENDPOINT} + headers: + Authorization: "${OTLP_API_TOKEN}" + debug: + verbosity: normal + extensions: + health_check: + endpoint: ${env:MY_POD_IP}:13133 + processors: + batch: {} + memory_limiter: + check_interval: 5s + limit_percentage: 80 + spike_limit_percentage: 25 + service: + extensions: + - health_check + pipelines: + traces: + receivers: [otlp] + processors: [] + exporters: [debug, otlphttp] + metrics: + exporters: [debug] + processors: [memory_limiter, batch] + receivers: [otlp] + logs: + receivers: [otlp] + processors: [memory_limiter, batch] + exporters: [debug] + telemetry: + metrics: + address: ${env:MY_POD_IP}:8888 diff --git a/opentelemetry-collector/chart/templates/deployment.yaml b/opentelemetry-collector/chart/templates/deployment.yaml new file mode 100644 index 000000000..2e6bb4680 --- /dev/null +++ b/opentelemetry-collector/chart/templates/deployment.yaml @@ -0,0 +1,56 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ .Values.collector.name }} +spec: + replicas: 1 + selector: + matchLabels: + app: {{ .Values.collector.name }} + template: + metadata: + labels: + app: {{ .Values.collector.name }} + spec: + containers: + - name: {{ .Values.collector.name }} + command: + - /otelcol-k8s + args: + - {{ toYaml .Values.collector.args | nindent 10 }} + image: "{{ .Values.global.registry }}/{{ .Values.global.odsNamespace }}/{{ .Values.collector.name }}:{{ .Values.global.odsImageTag }}" + ports: + {{- range .Values.collector.ports }} + - name: {{ .name }} + containerPort: {{ .port }} + {{- end }} + env: + {{- range .Values.collector.env }} + {{- if ne .name "OPENTELEMETRY_COLLECTOR_OTLP_API_TOKEN" }} + - name: {{ .name }} + value: "{{ .value }}" + {{- end }} + {{- end }} + - name: OTLP_API_TOKEN + valueFrom: + secretKeyRef: + name: {{ .Values.collector.name }}-secret + key: otlp-api-token + volumeMounts: + {{- range .Values.collector.volumeMounts }} + - name: {{ .name }} + mountPath: "{{ .mountPath }}" + {{- end }} + resources: + requests: + cpu: {{ .Values.collector.resources.requests.cpu | quote }} + memory: {{ .Values.collector.resources.requests.memory | quote }} + limits: + cpu: {{ .Values.collector.resources.limits.cpu | quote }} + memory: {{ .Values.collector.resources.limits.memory | quote }} + volumes: + {{- range .Values.collector.volumes }} + - name: {{ .name }} + configMap: + name: "{{ .configMap.name }}" + {{- end }} diff --git a/opentelemetry-collector/chart/templates/hpa.yaml b/opentelemetry-collector/chart/templates/hpa.yaml new file mode 100644 index 000000000..9ad944a61 --- /dev/null +++ b/opentelemetry-collector/chart/templates/hpa.yaml @@ -0,0 +1,32 @@ +{{- if .Values.autoscaling.enabled }} +apiVersion: autoscaling/v2 +kind: HorizontalPodAutoscaler +metadata: + name: {{ include "opentelemetry-collector.fullname" . }} + labels: + {{- include "opentelemetry-collector.labels" . | nindent 4 }} +spec: + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: {{ include "opentelemetry-collector.fullname" . }} + minReplicas: {{ .Values.autoscaling.minReplicas }} + maxReplicas: {{ .Values.autoscaling.maxReplicas }} + metrics: + {{- if .Values.autoscaling.targetCPUUtilizationPercentage }} + - type: Resource + resource: + name: cpu + target: + type: Utilization + averageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }} + {{- end }} + {{- if .Values.autoscaling.targetMemoryUtilizationPercentage }} + - type: Resource + resource: + name: memory + target: + type: Utilization + averageUtilization: {{ .Values.autoscaling.targetMemoryUtilizationPercentage }} + {{- end }} +{{- end }} diff --git a/opentelemetry-collector/chart/templates/imagestream.yml b/opentelemetry-collector/chart/templates/imagestream.yml new file mode 100644 index 000000000..62a15aabf --- /dev/null +++ b/opentelemetry-collector/chart/templates/imagestream.yml @@ -0,0 +1,9 @@ +apiVersion: image.openshift.io/v1 +kind: ImageStream +metadata: + labels: + app: {{ .Values.collector.name }} + name: {{ .Values.collector.name }} +spec: + lookupPolicy: + local: false diff --git a/opentelemetry-collector/chart/templates/ingress.yaml b/opentelemetry-collector/chart/templates/ingress.yaml new file mode 100644 index 000000000..09aaf4db7 --- /dev/null +++ b/opentelemetry-collector/chart/templates/ingress.yaml @@ -0,0 +1,46 @@ +{{- if .Values.ingress.enabled -}} +{{- $fullName := include "opentelemetry-collector.fullname" . -}} +{{- $svcPort := .Values.service.port -}} +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: {{ $fullName }}-ingress + namespace: {{ .Release.Namespace }} + labels: + {{- include "opentelemetry-collector.labels" . | nindent 4 }} + {{- with .Values.ingress.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + {{- if .Values.ingress.className }} + ingressClassName: {{ .Values.ingress.className }} + {{- end }} + {{- if .Values.ingress.tls }} + tls: + {{- range .Values.ingress.tls }} + - hosts: + {{- range .hosts }} + - {{ . | quote }} + {{- end }} + secretName: {{ .secretName }} + {{- end }} + {{- end }} + rules: + {{- range .Values.ingress.hosts }} + - host: {{ .host | quote }} + http: + paths: + {{- range .paths }} + - path: {{ .path }} + {{- if .pathType }} + pathType: {{ .pathType }} + {{- end }} + backend: + service: + name: {{ $.Values.service.name }} + port: + number: {{ $.Values.service.port }} + {{- end }} + {{- end }} +{{- end }} diff --git a/opentelemetry-collector/chart/templates/secret.yaml b/opentelemetry-collector/chart/templates/secret.yaml new file mode 100644 index 000000000..02f46498a --- /dev/null +++ b/opentelemetry-collector/chart/templates/secret.yaml @@ -0,0 +1,9 @@ +apiVersion: v1 +kind: Secret +metadata: + name: {{ .Values.collector.name }}-secret + labels: + app: {{ .Values.collector.name }} +type: Opaque +data: + otlp-api-token: {{ .Values.collector.secretValue | b64enc }} diff --git a/opentelemetry-collector/chart/templates/service.yaml b/opentelemetry-collector/chart/templates/service.yaml new file mode 100644 index 000000000..65469c8a2 --- /dev/null +++ b/opentelemetry-collector/chart/templates/service.yaml @@ -0,0 +1,28 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ .Values.service.name }} +spec: + selector: + app: {{ .Values.collector.name }} + ports: + - name: ui + protocol: TCP + port: 55679 + targetPort: 55679 + - name: another + protocol: TCP + port: 9464 + targetPort: 9464 + - name: other + protocol: TCP + port: 8888 + targetPort: 8888 + - name: tcp4317 + protocol: TCP + port: 4317 + targetPort: 4317 + - name: tcp4318 + protocol: TCP + port: 4318 + targetPort: 4318 diff --git a/opentelemetry-collector/chart/templates/tests/test-connection.yaml b/opentelemetry-collector/chart/templates/tests/test-connection.yaml new file mode 100644 index 000000000..d66b308c7 --- /dev/null +++ b/opentelemetry-collector/chart/templates/tests/test-connection.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Pod +metadata: + name: {{ include "opentelemetry-collector.fullname" . }}-test-connection + labels: + {{- include "opentelemetry-collector.labels" . | nindent 4 }} + annotations: + "helm.sh/hook": test +spec: + containers: + - name: wget + image: busybox + command: ['wget'] + args: ['{{ include "opentelemetry-collector.fullname" . }}:{{ .Values.service.port }}'] + restartPolicy: Never diff --git a/opentelemetry-collector/chart/values.yaml.template b/opentelemetry-collector/chart/values.yaml.template new file mode 100644 index 000000000..e47a5a192 --- /dev/null +++ b/opentelemetry-collector/chart/values.yaml.template @@ -0,0 +1,80 @@ +global: + registry: $DOCKER_REGISTRY + odsImageTag: $ODS_IMAGE_TAG + repoBase: $REPO_BASE + odsBitBucketProject: $ODS_BITBUCKET_PROJECT + odsGitRef: $ODS_GIT_REF + odsNamespace: $ODS_NAMESPACE +collector: + name: opentelemetry-collector + image: $OPENTELEMETRY_COLLECTOR_IMAGE + imageTag: $OPENTELEMETRY_COLLECTOR_IMAGE_TAG + args: ["--config=/conf/otel-collector-config.yaml"] + ports: + - name: otlp-grpc + port: 4317 + targetPort: 4317 + - name: otlp-http + port: 4318 + targetPort: 4318 + - name: jaeger-thrift + port: 55679 + targetPort: 55679 + - name: metrics + port: 8888 + targetPort: 8888 + - name: prometheus + port: 9464 + targetPort: 9464 + env: + - name: MY_POD_IP + valueFrom: + fieldRef: + fieldPath: status.podIP + - name: GOMEMLIMIT + value: $OPENTELEMETRY_COLLECTOR_GOMEMLIMIT + - name: OTLP_API_ENDPOINT + value: $OPENTELEMETRY_COLLECTOR_OTLP_API_ENDPOINT + secretValue: $OPENTELEMETRY_COLLECTOR_OTLP_API_TOKEN + volumeMounts: + - name: collector-config + mountPath: /conf + volumes: + - name: collector-config + configMap: + name: collector-config + items: + - key: otel-collector-config + path: otel-collector-config.yaml + defaultMode: 420 + resources: + requests: + cpu: $OPENTELEMETRY_COLLECTOR_CPU_REQUEST + memory: $OPENTELEMETRY_COLLECTOR_MEMORY_REQUEST + limits: + cpu: $OPENTELEMETRY_COLLECTOR_CPU_LIMIT + memory: $OPENTELEMETRY_COLLECTOR_MEMORY_LIMIT +service: + name: opentelemetry-collector-service + port: 4318 +ingress: + enabled: true + className: openshift-default + annotations: {} + tls: [] + hosts: + - host: $OPENTELEMETRY_COLLECTOR_INGRESS_HOST + paths: + - path: / + pathType: Prefix +autoscaling: + enabled: true + minReplicas: 1 + maxReplicas: 3 + targetCPUUtilizationPercentage: 80 + targetMemoryUtilizationPercentage: 80 +buildConfig: + cpuRequest: 200m + cpuLimit: 1 + memRequest: 128Mi + memLimit: 256Mi diff --git a/opentelemetry-collector/docker/Dockerfile b/opentelemetry-collector/docker/Dockerfile new file mode 100644 index 000000000..a04becd8f --- /dev/null +++ b/opentelemetry-collector/docker/Dockerfile @@ -0,0 +1,2 @@ +# FROM instruction is overwritten with OPENTELEMETRY_COLLECTOR_IMAGE and OPENTELEMETRY_COLLECTOR_IMAGE_TAG. +FROM otel/opentelemetry-collector-k8s:0.123.0-amd64