Skip to content

Commit 8be29bc

Browse files
committed
[autoinstrumentation] add ruby autoinstrumentation
1 parent 165a55a commit 8be29bc

32 files changed

+2965
-4
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
name: "Publish Ruby Auto-Instrumentation"
2+
3+
on:
4+
push:
5+
paths:
6+
- 'autoinstrumentation/ruby/**'
7+
- '.github/workflows/publish-autoinstrumentation-ruby.yaml'
8+
branches:
9+
- main
10+
pull_request:
11+
paths:
12+
- 'autoinstrumentation/ruby/**'
13+
- '.github/workflows/publish-autoinstrumentation-ruby.yaml'
14+
workflow_dispatch:
15+
16+
concurrency:
17+
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
18+
cancel-in-progress: true
19+
20+
21+
jobs:
22+
publish:
23+
runs-on: ubuntu-22.04
24+
25+
steps:
26+
- uses: actions/checkout@v4
27+
28+
- name: Read version
29+
run: echo "VERSION=$(cat autoinstrumentation/ruby/version.txt)" >> $GITHUB_ENV
30+
31+
- name: Docker meta
32+
id: meta
33+
uses: docker/metadata-action@v5
34+
with:
35+
images: |
36+
otel/autoinstrumentation-ruby
37+
ghcr.io/open-telemetry/opentelemetry-operator/autoinstrumentation-ruby
38+
tags: |
39+
type=match,pattern=v(.*),group=1,value=v${{ env.VERSION }}
40+
41+
- name: Set up QEMU
42+
uses: docker/setup-qemu-action@v3
43+
44+
- name: Set up Docker Buildx
45+
uses: docker/setup-buildx-action@v3
46+
47+
- name: Cache Docker layers
48+
uses: actions/cache@v4
49+
with:
50+
path: /tmp/.buildx-cache
51+
key: ${{ runner.os }}-buildx-${{ github.sha }}
52+
restore-keys: |
53+
${{ runner.os }}-buildx-
54+
55+
- name: Log into Docker.io
56+
uses: docker/login-action@v3
57+
if: ${{ github.event_name == 'push' }}
58+
with:
59+
username: ${{ secrets.DOCKER_USERNAME }}
60+
password: ${{ secrets.DOCKER_PASSWORD }}
61+
62+
- name: Login to GitHub Package Registry
63+
uses: docker/login-action@v3
64+
if: ${{ github.event_name == 'push' }}
65+
with:
66+
registry: ghcr.io
67+
username: ${{ github.repository_owner }}
68+
password: ${{ secrets.GITHUB_TOKEN }}
69+
70+
- name: Build and push
71+
uses: docker/build-push-action@v6
72+
with:
73+
context: autoinstrumentation/ruby
74+
platforms: linux/amd64,linux/arm64,linux/s390x,linux/ppc64le
75+
push: ${{ github.event_name == 'push' }}
76+
build-args: version=${{ env.VERSION }}
77+
tags: ${{ steps.meta.outputs.tags }}
78+
labels: ${{ steps.meta.outputs.labels }}
79+
cache-from: type=local,src=/tmp/.buildx-cache
80+
cache-to: type=local,dest=/tmp/.buildx-cache

Makefile

+3-1
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,13 @@ OPERATOR_OPAMP_BRIDGE_VERSION ?= "$(shell grep -v '\#' versions.txt | grep opera
99
AUTO_INSTRUMENTATION_JAVA_VERSION ?= "$(shell grep -v '\#' versions.txt | grep autoinstrumentation-java | awk -F= '{print $$2}')"
1010
AUTO_INSTRUMENTATION_NODEJS_VERSION ?= "$(shell grep -v '\#' versions.txt | grep autoinstrumentation-nodejs | awk -F= '{print $$2}')"
1111
AUTO_INSTRUMENTATION_PYTHON_VERSION ?= "$(shell grep -v '\#' versions.txt | grep autoinstrumentation-python | awk -F= '{print $$2}')"
12+
AUTO_INSTRUMENTATION_RUBY_VERSION ?= "$(shell grep -v '\#' versions.txt | grep autoinstrumentation-ruby | awk -F= '{print $$2}')"
1213
AUTO_INSTRUMENTATION_DOTNET_VERSION ?= "$(shell grep -v '\#' versions.txt | grep autoinstrumentation-dotnet | awk -F= '{print $$2}')"
1314
AUTO_INSTRUMENTATION_GO_VERSION ?= "$(shell grep -v '\#' versions.txt | grep autoinstrumentation-go | awk -F= '{print $$2}')"
1415
AUTO_INSTRUMENTATION_APACHE_HTTPD_VERSION ?= "$(shell grep -v '\#' versions.txt | grep autoinstrumentation-apache-httpd | awk -F= '{print $$2}')"
1516
AUTO_INSTRUMENTATION_NGINX_VERSION ?= "$(shell grep -v '\#' versions.txt | grep autoinstrumentation-nginx | awk -F= '{print $$2}')"
1617
COMMON_LDFLAGS ?= -s -w
17-
OPERATOR_LDFLAGS ?= -X ${VERSION_PKG}.version=${VERSION} -X ${VERSION_PKG}.buildDate=${VERSION_DATE} -X ${VERSION_PKG}.otelCol=${OTELCOL_VERSION} -X ${VERSION_PKG}.targetAllocator=${TARGETALLOCATOR_VERSION} -X ${VERSION_PKG}.operatorOpAMPBridge=${OPERATOR_OPAMP_BRIDGE_VERSION} -X ${VERSION_PKG}.autoInstrumentationJava=${AUTO_INSTRUMENTATION_JAVA_VERSION} -X ${VERSION_PKG}.autoInstrumentationNodeJS=${AUTO_INSTRUMENTATION_NODEJS_VERSION} -X ${VERSION_PKG}.autoInstrumentationPython=${AUTO_INSTRUMENTATION_PYTHON_VERSION} -X ${VERSION_PKG}.autoInstrumentationDotNet=${AUTO_INSTRUMENTATION_DOTNET_VERSION} -X ${VERSION_PKG}.autoInstrumentationGo=${AUTO_INSTRUMENTATION_GO_VERSION} -X ${VERSION_PKG}.autoInstrumentationApacheHttpd=${AUTO_INSTRUMENTATION_APACHE_HTTPD_VERSION} -X ${VERSION_PKG}.autoInstrumentationNginx=${AUTO_INSTRUMENTATION_NGINX_VERSION}
18+
OPERATOR_LDFLAGS ?= -X ${VERSION_PKG}.version=${VERSION} -X ${VERSION_PKG}.buildDate=${VERSION_DATE} -X ${VERSION_PKG}.otelCol=${OTELCOL_VERSION} -X ${VERSION_PKG}.targetAllocator=${TARGETALLOCATOR_VERSION} -X ${VERSION_PKG}.operatorOpAMPBridge=${OPERATOR_OPAMP_BRIDGE_VERSION} -X ${VERSION_PKG}.autoInstrumentationJava=${AUTO_INSTRUMENTATION_JAVA_VERSION} -X ${VERSION_PKG}.autoInstrumentationNodeJS=${AUTO_INSTRUMENTATION_NODEJS_VERSION} -X ${VERSION_PKG}.autoInstrumentationPython=${AUTO_INSTRUMENTATION_PYTHON_VERSION} -X ${VERSION_PKG}.autoInstrumentationRuby=${AUTO_INSTRUMENTATION_RUBY_VERSION} -X ${VERSION_PKG}.autoInstrumentationDotNet=${AUTO_INSTRUMENTATION_DOTNET_VERSION} -X ${VERSION_PKG}.autoInstrumentationGo=${AUTO_INSTRUMENTATION_GO_VERSION} -X ${VERSION_PKG}.autoInstrumentationApacheHttpd=${AUTO_INSTRUMENTATION_APACHE_HTTPD_VERSION} -X ${VERSION_PKG}.autoInstrumentationNginx=${AUTO_INSTRUMENTATION_NGINX_VERSION}
1819
ARCH ?= $(shell go env GOARCH)
1920
ifeq ($(shell uname), Darwin)
2021
SED_INPLACE := sed -i ''
@@ -667,6 +668,7 @@ chlog-insert-components:
667668
@echo "* [.NET auto-instrumentation - v${AUTO_INSTRUMENTATION_DOTNET_VERSION}](https://github.com/open-telemetry/opentelemetry-dotnet-instrumentation/releases/tag/v${AUTO_INSTRUMENTATION_DOTNET_VERSION})" >>components.md
668669
@echo "* [Node.JS - v${AUTO_INSTRUMENTATION_NODEJS_VERSION}](https://github.com/open-telemetry/opentelemetry-js/releases/tag/experimental%2Fv${AUTO_INSTRUMENTATION_NODEJS_VERSION})" >>components.md
669670
@echo "* [Python - v${AUTO_INSTRUMENTATION_PYTHON_VERSION}](https://github.com/open-telemetry/opentelemetry-python-contrib/releases/tag/v${AUTO_INSTRUMENTATION_PYTHON_VERSION})" >>components.md
671+
@echo "* [Ruby - v${AUTO_INSTRUMENTATION_RUBY_VERSION}](https://github.com/open-telemetry/opentelemetry-ruby-contrib/releases/tag/v${AUTO_INSTRUMENTATION_RUBY_VERSION})" >>components.md
670672
@echo "* [Go - ${AUTO_INSTRUMENTATION_GO_VERSION}](https://github.com/open-telemetry/opentelemetry-go-instrumentation/releases/tag/${AUTO_INSTRUMENTATION_GO_VERSION})" >>components.md
671673
@echo "* [ApacheHTTPD - ${AUTO_INSTRUMENTATION_APACHE_HTTPD_VERSION}](https://github.com/open-telemetry/opentelemetry-cpp-contrib/releases/tag/webserver%2Fv${AUTO_INSTRUMENTATION_APACHE_HTTPD_VERSION})" >>components.md
672674
@echo "* [Nginx - ${AUTO_INSTRUMENTATION_NGINX_VERSION}](https://github.com/open-telemetry/opentelemetry-cpp-contrib/releases/tag/webserver%2Fv${AUTO_INSTRUMENTATION_NGINX_VERSION})" >>components.md

apis/v1alpha1/instrumentation_types.go

+28
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,10 @@ type InstrumentationSpec struct {
5050
// +optional
5151
Python Python `json:"python,omitempty"`
5252

53+
// Ruby defines configuration for Ruby auto-instrumentation.
54+
// +optional
55+
Ruby Ruby `json:"ruby,omitempty"`
56+
5357
// DotNet defines configuration for DotNet auto-instrumentation.
5458
// +optional
5559
DotNet DotNet `json:"dotnet,omitempty"`
@@ -232,6 +236,30 @@ type Python struct {
232236
Resources corev1.ResourceRequirements `json:"resourceRequirements,omitempty"`
233237
}
234238

239+
type Ruby struct {
240+
// Image is a container image with Ruby SDK and auto-instrumentation.
241+
// +optional
242+
Image string `json:"image,omitempty"`
243+
244+
// VolumeClaimTemplate defines a ephemeral volume used for auto-instrumentation.
245+
// If omitted, an emptyDir is used with size limit VolumeSizeLimit
246+
VolumeClaimTemplate corev1.PersistentVolumeClaimTemplate `json:"volumeClaimTemplate,omitempty"`
247+
248+
// VolumeSizeLimit defines size limit for volume used for auto-instrumentation.
249+
// The default size is 200Mi.
250+
VolumeSizeLimit *resource.Quantity `json:"volumeLimitSize,omitempty"`
251+
252+
// Env defines Ruby specific env vars. There are four layers for env vars' definitions and
253+
// the precedence order is: `original container env vars` > `language specific env vars` > `common env vars` > `instrument spec configs' vars`.
254+
// If the former var had been defined, then the other vars would be ignored.
255+
// +optional
256+
Env []corev1.EnvVar `json:"env,omitempty"`
257+
258+
// Resources describes the compute resource requirements.
259+
// +optional
260+
Resources corev1.ResourceRequirements `json:"resourceRequirements,omitempty"`
261+
}
262+
235263
// DotNet defines DotNet SDK and instrumentation configuration.
236264
type DotNet struct {
237265
// Image is a container image with DotNet SDK and auto-instrumentation.

apis/v1alpha1/instrumentation_webhook.go

+20
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,21 @@ func (w InstrumentationWebhook) defaulter(r *Instrumentation) error {
126126
corev1.ResourceMemory: resource.MustParse("64Mi"),
127127
}
128128
}
129+
if r.Spec.Ruby.Image == "" {
130+
r.Spec.Ruby.Image = w.cfg.AutoInstrumentationRubyImage()
131+
}
132+
if r.Spec.Ruby.Resources.Limits == nil {
133+
r.Spec.Ruby.Resources.Limits = corev1.ResourceList{
134+
corev1.ResourceCPU: resource.MustParse("500m"),
135+
corev1.ResourceMemory: resource.MustParse("128Mi"),
136+
}
137+
}
138+
if r.Spec.Ruby.Resources.Requests == nil {
139+
r.Spec.Ruby.Resources.Requests = corev1.ResourceList{
140+
corev1.ResourceCPU: resource.MustParse("50m"),
141+
corev1.ResourceMemory: resource.MustParse("128Mi"),
142+
}
143+
}
129144
if r.Spec.DotNet.Image == "" {
130145
r.Spec.DotNet.Image = w.cfg.AutoInstrumentationDotNetImage()
131146
}
@@ -190,6 +205,7 @@ func (w InstrumentationWebhook) defaulter(r *Instrumentation) error {
190205
r.Annotations[constants.AnnotationDefaultAutoInstrumentationJava] = w.cfg.AutoInstrumentationJavaImage()
191206
r.Annotations[constants.AnnotationDefaultAutoInstrumentationNodeJS] = w.cfg.AutoInstrumentationNodeJSImage()
192207
r.Annotations[constants.AnnotationDefaultAutoInstrumentationPython] = w.cfg.AutoInstrumentationPythonImage()
208+
r.Annotations[constants.AnnotationDefaultAutoInstrumentationRuby] = w.cfg.AutoInstrumentationRubyImage()
193209
r.Annotations[constants.AnnotationDefaultAutoInstrumentationDotNet] = w.cfg.AutoInstrumentationDotNetImage()
194210
r.Annotations[constants.AnnotationDefaultAutoInstrumentationGo] = w.cfg.AutoInstrumentationGoImage()
195211
r.Annotations[constants.AnnotationDefaultAutoInstrumentationApacheHttpd] = w.cfg.AutoInstrumentationApacheHttpdImage()
@@ -256,6 +272,10 @@ func (w InstrumentationWebhook) validate(r *Instrumentation) (admission.Warnings
256272
if err != nil {
257273
return warnings, fmt.Errorf("spec.python.volumeClaimTemplate and spec.python.volumeSizeLimit cannot both be defined: %w", err)
258274
}
275+
err = validateInstrVolume(r.Spec.Ruby.VolumeClaimTemplate, r.Spec.Ruby.VolumeSizeLimit)
276+
if err != nil {
277+
return warnings, fmt.Errorf("spec.ruby.volumeClaimTemplate and spec.ruby.volumeSizeLimit cannot both be defined: %w", err)
278+
}
259279

260280
warnings = append(warnings, validateExporter(r.Spec.Exporter)...)
261281

apis/v1alpha1/instrumentation_webhook_test.go

+2
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ func TestInstrumentationDefaultingWebhook(t *testing.T) {
2424
config.WithAutoInstrumentationJavaImage("java-img:1"),
2525
config.WithAutoInstrumentationNodeJSImage("nodejs-img:1"),
2626
config.WithAutoInstrumentationPythonImage("python-img:1"),
27+
config.WithAutoInstrumentationRubyImage("ruby-img:1"),
2728
config.WithAutoInstrumentationDotNetImage("dotnet-img:1"),
2829
config.WithAutoInstrumentationApacheHttpdImage("apache-httpd-img:1"),
2930
config.WithAutoInstrumentationNginxImage("nginx-img:1"),
@@ -33,6 +34,7 @@ func TestInstrumentationDefaultingWebhook(t *testing.T) {
3334
assert.Equal(t, "java-img:1", inst.Spec.Java.Image)
3435
assert.Equal(t, "nodejs-img:1", inst.Spec.NodeJS.Image)
3536
assert.Equal(t, "python-img:1", inst.Spec.Python.Image)
37+
assert.Equal(t, "ruby-img:1", inst.Spec.Ruby.Image)
3638
assert.Equal(t, "dotnet-img:1", inst.Spec.DotNet.Image)
3739
assert.Equal(t, "apache-httpd-img:1", inst.Spec.ApacheHttpd.Image)
3840
assert.Equal(t, "nginx-img:1", inst.Spec.Nginx.Image)

apis/v1alpha1/zz_generated.deepcopy.go

+30
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

autoinstrumentation/ruby/Dockerfile

+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
# To build one auto-instrumentation image for Ruby, please:
2+
# - Ensure the packages are installed in the `/autoinstrumentation` directory. This is required as when instrumenting the pod,
3+
# one init container will be created to copy all the content in `/autoinstrumentation` directory to your app's container. Then
4+
# update the `RUBYOPT` environment variable accordingly. To achieve this, you can mimic the one in `autoinstrumentation/ruby/Dockerfile`
5+
# by using multi-stage builds. In the first stage, install all the required packages in one custom directory.
6+
# Then in the second stage, copy the directory to `/autoinstrumentation`.
7+
# - Ensure you have `opentelemetry-sdk`, `opentelemetry-instrumentation-all`, and `opentelemetry-exporter-otlp` or your customized
8+
# alternatives installed.
9+
# - Grant the necessary access to `/autoinstrumentation` directory. `chmod -R go+r /autoinstrumentation`
10+
# - For auto-instrumentation by container injection, the Linux command cp is
11+
# used and must be availabe in the image.
12+
FROM ruby:3.3-slim AS build
13+
14+
ARG PACKAGES="\
15+
build-essential \
16+
"
17+
18+
# Install packages
19+
RUN apt-get update && \
20+
apt-get upgrade -y && \
21+
apt-get install -y --no-install-recommends ${PACKAGES} && \
22+
apt-get clean && \
23+
rm -rf /var/lib/apt/lists/*
24+
25+
WORKDIR /ruby/instrumentation
26+
27+
COPY . .
28+
29+
RUN gem install opentelemetry-api -v '1.4.0' --install-dir ./ && \
30+
gem install opentelemetry-exporter-otlp -v '0.29.1' --install-dir ./ && \
31+
gem install opentelemetry-helpers-mysql -v '0.2.0' --install-dir ./ && \
32+
gem install opentelemetry-helpers-sql-obfuscation -v '0.3.0' --install-dir ./ && \
33+
gem install opentelemetry-instrumentation-all -v '0.72.0' --install-dir ./ && \
34+
gem install opentelemetry-resource-detector-azure -v '0.2.0' --install-dir ./ && \
35+
gem install opentelemetry-resource-detector-container -v '0.2.0' --install-dir ./ && \
36+
gem install opentelemetry-resource-detector-google_cloud_platform -v '0.2.0' --install-dir ./ && \
37+
gem install opentelemetry-sdk -v '1.6.0' --install-dir ./
38+
39+
FROM busybox
40+
41+
# copy all gems from global install to autoinstrumentation
42+
COPY --from=build /ruby/instrumentation/ /autoinstrumentation
43+
44+
RUN chmod -R go+r /autoinstrumentation

0 commit comments

Comments
 (0)