Feedforce Developer Blog

フィードフォース開発者ブログ

Sentry に Rust アプリケーションの Debug Information File をアップロードする

お久しぶりです. Omni Hub チームの shunten31 です. 早朝に散歩する習慣があるのですが、 朝の風がひんやりしてきましたね.

今回は、 Sentry に Rust アプリケーションの Debug Information File をアップロードするように、デプロイフローを改修したので、その方法について紹介していきます.

Sentry では、 アプリケーションの実行ファイルに対応する Debug Information Files を事前にアップロードすることで、 エラー発生時の Sentry イベントにスタックトレース情報を付加できるのですが、実際のデプロイフローにおいて Sentry に Debug Information File アップロードする具体的方法や事例が、 英語・日本語問わず見当たりませんでした. 紹介する方法が最善かはわかりませんが、どなたかの参考になればと思い、実施方法を紹介させていただきます.

現状の Docker イメージのビルドフロー

現在利用している Dockerfile から、 関連部分を抜粋したものを以下に示します. マルチステージビルドを用いており、 rust-builder ステージでビルドを行い、 app ステージが最終的な実行環境となります.

Dockerfile

FROM amazonlinux-base AS rust-builder
WORKDIR /app
COPY . .
RUN cargo build --release --bin server --bin worker \
    && mkdir -p /dist \
  && (find target/release -maxdepth 1 -type f | xargs -I{} cp "{}" /dist)
  
FROM amazonlinux-base AS app
WORKDIR /app
COPY --from=rust-builder /dist bin
CMD ["bin/server"]
EXPOSE 5000 5001

上記 Dockerfile の app ステージは、 GitHub Actions を利用して ECR にアップロードしています.

GitHub Actions

- uses: docker/build-push-action@v6
  id: docker_build
  with:
    builder: ${{ steps.docker-builder.outputs.name }}
    context: .
    target: app
    push: true

Debug Information File の作成

公式ドキュメント に従って、 Debug Information File を作成します.

まず、 Cargo.toml を編集して、 release build にもデバッグ情報が含まれるようにします.

[profile.release]
debug = true

次に、 実行ファイル(この例では serverworker)からデバッグファイルを抽出します.

objcopy --only-keep-debug target/release/app{,.d}
objcopy --strip-debug --strip-unneeded target/release/app
objcopy --add-gnu-debuglink target/release/app{.d,}

各コマンドの役割は以下の通りです.

  1. app のデバッグ情報を app.d へ抽出します
  2. app からデバッグ情報などの不要情報を削ります. これで実行ファイルが軽くなります
  3. app バイナリに app.d というデバッグシンボルファイルが存在するというリンク情報を埋め込みます

この処理を Docker イメージのビルドステップに組み込みます.

FROM amazonlinux-base AS rust-builder
WORKDIR /app
COPY . .
RUN cargo build --release --bin server --bin worker \
  && mkdir -p /dist \
  && objcopy --only-keep-debug target/release/server{,.d} \
  && objcopy --strip-debug --strip-unneeded target/release/server \
  && objcopy --add-gnu-debuglink target/release/server{.d,} \
  && objcopy --only-keep-debug target/release/worker{,.d} \
  && objcopy --strip-debug --strip-unneeded target/release/worker \
  && objcopy --add-gnu-debuglink target/release/worker{.d,} \
  && (find target/release -maxdepth 1 -type f | xargs -I{} cp "{}" /dist) \

Debug Information File の抽出

現状では、 Debug Information File は Docker イメージのビルドステップ内部にしか存在しません. そのため、 必要なファイルをビルドの外部へエクスポートする必要があります.

これを行うには、Export binaries | Docker Docs を参考に、 エクスポート用のビルドステージを定義します. なお、 scratch イメージは最小構成の空イメージです.

 FROM amazonlinux-base AS rust-builder
 WORKDIR /app
 COPY . .
 RUN cargo build --release --bin server --bin worker \
-  && mkdir -p /dist \
+  && mkdir -p /dist /target/release \
   && objcopy --only-keep-debug target/release/server{,.d} \
   && objcopy --strip-debug --strip-unneeded target/release/server \
   && objcopy --add-gnu-debuglink target/release/server{.d,} \
@@
   && objcopy --add-gnu-debuglink target/release/worker{.d,} \
   && (find target/release -maxdepth 1 -type f | xargs -I{} cp "{}" /dist) \
+  && cp target/release/server target/release/server.d \
+        target/release/worker target/release/worker.d \
+        /target/release/

+ FROM scratch AS export
+ COPY --from=rust-builder /target /target

build-push-action@v6 を利用することで、 export ステージをビルドしています. outputs: type=local,dest=./target-export を設定しているので、 export ステージのファイルが、 CI 実行マシン上の ./target-export にコピーされます.

※ なお、 push: false に設定されているので、 ビルドしたイメージはレポジトリにプッシュされることはありません.

さらに、 コピーされたファイルを後続ジョブで利用できるよう artifact としてアップロードしておきます.

- uses: docker/build-push-action@v6
  id: export_target
  with:
    builder: ${{ steps.docker-builder.outputs.name }}
    context: .
    target: export
    push: false
    outputs: type=local,dest=./target-export
- name: Upload artifact
  uses: actions/upload-artifact@v4
  with:
    name: target-export
    path: ./target-export/target
    retention-days: 14

Debug Information File を Sentry にアップロード

別のジョブで、 先ほど artifact として保存したファイルを取得し、 Sentry にアップロードします.

upload-debug-files:
  name: Upload debug files
  runs-on: ubuntu-22.04
  needs: app  # artifact を upload したジョブ名 
  steps:
    - name: Download artifact
      uses: actions/download-artifact@v4
      with:
        name: target-export
    - name: Install Sentry CLI
      env:
        SENTRY_CLI_VERSION: 2.54.0
      run: |
        curl -sL https://sentry.io/get-cli/ | sh
    - name: Upload debug files to Sentry
      env:
        SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
        SENTRY_ORG: "***"
        SENTRY_PROJECT: server
      run: |
        sentry-cli debug-files upload --include-sources ./release

動作確認

このフローで作成したアプリケーションのイメージをデプロイすれば、 Sentry の Issue 上で事前にアップロードした Debug Information File が自動的に検知され、スタックトレース情報が表示されます.

Sentry で Debug Information File が関連付けられている