Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 12 additions & 8 deletions .github/actions/build-ruby-layer/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,21 @@ outputs:
runs:
using: composite
steps:
- name: Build Ruby layer
shell: bash
working-directory: ruby/src
run: ./build.sh

- name: Save Ruby OpenTelemetry SDK version
id: version
shell: bash
working-directory: ruby/src
run: |
unzip -q build/opentelemetry-ruby-layer.zip
export GEM_PATH=$PWD/ruby/gems/3.3.0/
SDK_VERSION=$(ruby -e 'require "opentelemetry-sdk"; puts OpenTelemetry::SDK::VERSION')
SDK_VERSION=$(sed -n 's/^ opentelemetry-sdk (\([^)]*\))$/\1/p' otel/layer/Gemfile.lock)
echo "component-version=$SDK_VERSION" >> "$GITHUB_OUTPUT"

# The layer also contains arm64 gems, built in emulated arm64 stages.
- name: Set up QEMU
uses: docker/setup-qemu-action@99012661954931238ded8c8b007157a8430204e1 # v4.4.0
with:
platforms: arm64

- name: Build Ruby layer
shell: bash
working-directory: ruby/src
run: ./build.sh
6 changes: 3 additions & 3 deletions .github/workflows/ci-ruby.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,14 @@ on:
paths:
- 'ruby/**'
- '.github/workflows/ci-ruby.yml'
- '.github/actions/build-ruby-layer/**'
branches:
- main
pull_request:
paths:
- 'ruby/**'
- '.github/workflows/ci-ruby.yml'
- '.github/actions/build-ruby-layer/**'
branches:
- main

Expand All @@ -25,6 +27,4 @@ jobs:
with:
persist-credentials: false
- name: Build Ruby layer
shell: bash
working-directory: ruby/src
run: ./build.sh
uses: $/.github/actions/build-ruby-layer
1 change: 1 addition & 0 deletions integration-tests/tests/layer.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ describe(`${language} Lambda layer`, () => {
}),
);
expect(response.StatusCode).toBe(200);
expect(response.FunctionError).toBeUndefined();

const payload = JSON.parse(new TextDecoder().decode(response.Payload));
const body = JSON.parse(payload.body);
Expand Down
3 changes: 1 addition & 2 deletions ruby/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
Scripts and files used to build AWS Lambda Layers for running OpenTelemetry on AWS Lambda for Ruby.

**Requirement**
* Ruby 3.3.0/3.4.0
* [SAM CLI](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html)
* [AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/install-cliv2.html)
* [Go](https://go.dev/doc/install)
Expand All @@ -17,7 +16,7 @@ Scripts and files used to build AWS Lambda Layers for running OpenTelemetry on A
./build.sh
```

Layer is stored in `src/build` folder
Layer is stored in `src/build`. It contains gems for Ruby 3.3 and 3.4 on x86_64 and arm64. Only Docker is needed; building the non-native architecture needs QEMU binfmt (e.g. `docker run --privileged --rm tonistiigi/binfmt --install all`).

**Default GEM_PATH**

Expand Down
104 changes: 45 additions & 59 deletions ruby/src/otel/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,60 +1,46 @@
FROM ubuntu:26.04@sha256:f144425ff09be612d6d9ad965196e9cdc23dae1f42110a8a11a3e9a8198759f7

RUN mkdir /build

COPY . /build

RUN apt-get update && apt-get install -y git curl libssl-dev libreadline-dev zlib1g-dev autoconf bison build-essential libyaml-dev libreadline-dev libncurses5-dev libffi-dev libgdbm-dev zip

RUN git clone https://github.com/rbenv/rbenv.git ~/.rbenv \
&& git clone https://github.com/rbenv/ruby-build.git ~/.rbenv/plugins/ruby-build \
&& git clone https://github.com/rbenv/rbenv-default-gems.git ~/.rbenv/plugins/rbenv-default-gems \
&& echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.profile \
&& echo 'eval "$(rbenv init -)"' >> ~/.profile \
&& echo 'eval "$(rbenv init -)"' >> ~/.bashrc \
&& echo 'bundler' > ~/.rbenv/default-gems

RUN echo 'alias be="bundle exec"' >> ~/.bashrc
RUN echo 'alias be="bundle exec"' >> ~/.profile

# install rubies to build our gem against Gemfile
RUN . ~/.profile \
&& cd /root/.rbenv/plugins/ruby-build && git pull && cd - \
&& rbenv install 3.3.0 \
&& rbenv install 3.4.0

WORKDIR /build/layer

RUN . ~/.profile && rbenv local 3.3.0 && bundle install
RUN . ~/.profile && rbenv local 3.4.0 && bundle install

WORKDIR /root/.rbenv/versions/3.3.0/lib/ruby/gems/
RUN zip -r gems-3.3.0.zip 3.3.0/

WORKDIR /root/.rbenv/versions/3.4.0/lib/ruby/gems/

# rbenv install 3.4.0 get 3.4.0+1/, so need to change back to 3.4.0+1
RUN mv 3.4.0+1/ 3.4.0/
RUN set -e && \
dir=$(find /root/.rbenv/versions/3.4.0/lib/ruby/gems/ -type d -name '3.4.0+1' | head -n 1) && \
target=$(echo "$dir" | sed 's/3\.4\.0+1/3.4.0/') && \
mv "$dir" "$target"
RUN zip -r gems-3.4.0.zip 3.4.0/

# copy gems to /build/ruby/gems for zipping
RUN mkdir /build/ruby && mkdir /build/ruby/gems
WORKDIR /build/ruby/gems
RUN cp /root/.rbenv/versions/3.3.0/lib/ruby/gems/gems-3.3.0.zip . && unzip gems-3.3.0.zip && rm gems-3.3.0.zip
RUN cp /root/.rbenv/versions/3.4.0/lib/ruby/gems/gems-3.4.0.zip . && unzip gems-3.4.0.zip && rm gems-3.4.0.zip
RUN ls -al /build/ruby/gems

# rm gem cache
RUN rm /root/.rbenv/versions/3.3.0/lib/ruby/gems/3.3.0/cache/* \
&& rm /root/.rbenv/versions/3.4.0/lib/ruby/gems/3.4.0/cache/*

# zip all the gems
# Builds one layer with gems for Ruby 3.3 and 3.4 on both x86_64 and arm64.
# RubyGems only activates gem specs whose platform matches the running
# machine, so both architectures' gems can live side by side in
# ruby/gems/<X.Y.0>. The four install stages below are independent, so
# BuildKit runs them in parallel (arm64 via QEMU on amd64 hosts and vice versa).

FROM --platform=linux/amd64 public.ecr.aws/sam/build-ruby3.3:latest@sha256:0e8b401558ba3d59722ea169d0da854631136a23eded32109d6a8ed2345ab0ee AS ruby3.3-amd64
COPY layer/Gemfile layer/Gemfile.lock install-gems.sh /build/
RUN /build/install-gems.sh

FROM --platform=linux/arm64 public.ecr.aws/sam/build-ruby3.3:latest@sha256:0e8b401558ba3d59722ea169d0da854631136a23eded32109d6a8ed2345ab0ee AS ruby3.3-arm64
COPY layer/Gemfile layer/Gemfile.lock install-gems.sh /build/
RUN /build/install-gems.sh

FROM --platform=linux/amd64 public.ecr.aws/sam/build-ruby3.4:latest@sha256:a208c01413754ea473357ffdc850fab3cdadf6dac776a0566242464dba2aa02b AS ruby3.4-amd64
COPY layer/Gemfile layer/Gemfile.lock install-gems.sh /build/
RUN /build/install-gems.sh

FROM --platform=linux/arm64 public.ecr.aws/sam/build-ruby3.4:latest@sha256:a208c01413754ea473357ffdc850fab3cdadf6dac776a0566242464dba2aa02b AS ruby3.4-arm64
COPY layer/Gemfile layer/Gemfile.lock install-gems.sh /build/
RUN /build/install-gems.sh

# Final stage only merges and zips, so it runs on the host's native platform.
FROM public.ecr.aws/sam/build-ruby3.3:latest@sha256:0e8b401558ba3d59722ea169d0da854631136a23eded32109d6a8ed2345ab0ee
WORKDIR /build
RUN cp layer/otel-handler . && cp layer/wrapper.rb .
RUN zip -r opentelemetry-ruby-layer.zip ruby/ otel-handler wrapper.rb

CMD cp /build/opentelemetry-ruby-layer.zip /out/opentelemetry-ruby-layer.zip
COPY --from=ruby3.3-amd64 /gems/ruby/ amd64/
COPY --from=ruby3.4-amd64 /gems/ruby/ amd64/
COPY --from=ruby3.3-arm64 /gems/ruby/ arm64/
COPY --from=ruby3.4-arm64 /gems/ruby/ arm64/

# Paths that exist for both architectures must be identical, otherwise one
# would overwrite the other in the merged layer. Fail if a (future) native
# gem brings such a clash back.
RUN if diff -rq amd64 arm64 2>&1 | grep -v '^Only in '; then \
echo "ERROR: amd64 and arm64 gem trees clash on the paths above" >&2; exit 1; \
fi

RUN mkdir -p ruby/gems \
&& cp -a amd64/. ruby/gems/ \
&& cp -a arm64/. ruby/gems/

COPY layer/otel-handler ./
COPY layer/wrapper.rb ./
RUN zip -qr opentelemetry-ruby-layer.zip ruby/ otel-handler wrapper.rb

CMD ["cp", "/build/opentelemetry-ruby-layer.zip", "/out/opentelemetry-ruby-layer.zip"]
20 changes: 20 additions & 0 deletions ruby/src/otel/install-gems.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#!/bin/sh
# Installs the layer's gems for the Ruby version and architecture of the
# current build image into /gems/ruby/<X.Y.0>, keeping only what ships.
set -eu

# Without this RubyGems also copies compiled extensions (e.g. bigdecimal.so)
# into gems/<name>/lib/, an arch-agnostic path that would clash between
# amd64 and arm64. The copy under extensions/<arch>-linux/ is enough.
echo "install_extension_in_lib: false" > ~/.gemrc

# BUNDLE_VERSION=system: use the image's Bundler instead of installing the
# lockfile's "BUNDLED WITH" version into the layer.
cd /build
BUNDLE_PATH=/gems BUNDLE_FROZEN=true BUNDLE_VERSION=system \
bundle install --jobs "$(nproc)"

# Drop download cache, docs, build leftovers, binstubs and build logs.
cd /gems/ruby/*/
rm -rf cache doc build_info bin plugins gems/*/ext
find extensions \( -name mkmf.log -o -name gem_make.out \) -delete
Loading