ようへいの日々精進XP

よかろうもん

おそらく 20 分くらいで Elastic APM を試す

これは

New Relic や Datadog の APM 以外の APM を探して三千里している過程で、無料で試せる Elastic APM に出会ったので、Docker を利用して Elastic APM を動かす環境 (Rails を利用する) を作ってみたのでメモしておきます。

Elastic APM とは

f:id:inokara:20220313185743p:plain

あの Elastic 社が提供している APM (Application Performance Monitoring/Management) サービスで、アプリケーションのパフォーマンス監視ができるソフトウェアです。

www.elastic.co

Elastic APM の特徴としては、

  • OSS として提供されているので、ソフトウェア自体は無償で利用出来る
  • 多少馴染みのある Kibana で利用出来る
  • エラー情報 (Stack Trace 等の情報) も統合することが出来る (らしい
  • もちろん、Ruby や Rails でも利用出来る

Elastic APM 5min Setup

用意するもの

リポジトリ

github.com

注意

  • 事前に Docker と docker-compose が利用出来るようにしておくこと

docker-compose.yml

version: '3'

services:
  elasticsearch:
    image: docker.elastic.co/elasticsearch/elasticsearch:7.7.1
    environment:
      - discovery.type=single-node
      - bootstrap.memory_lock=true
      - cluster.name=docker-cluster
      - cluster.routing.allocation.disk.threshold_enabled=false
      - ES_JAVA_OPTS=-Xms512m -Xmx512m
    volumes:
      - es_data:/usr/share/elasticsearch
    ports:
      - 9200:9200
    ulimits:
      memlock:
        soft: -1
        hard: -1

  apm:
    image: docker.elastic.co/apm/apm-server:7.7.1
    volumes:
      - ./apm/apm-server.yml:/usr/share/apm-server/apm-server.yml
    depends_on:
      - elasticsearch
      - kibana
    ports:
      - 8200:8200

  kibana:
    image: docker.elastic.co/kibana/kibana:7.7.1
    depends_on:
      - elasticsearch
    environment:
      ELASTICSEARCH_URL: http://elasticsearch:9200
      ELASTICSEARCH_HOSTS: http://elasticsearch:9200
    ports:
      - 5601:5601

  api:
    build: .
    ports:
      - "3000:3000"
    depends_on:
      - db
    volumes:
      - .:/app
    environment:
      ELASTIC_APM_SERVER_URL: http://apm:8200
    command: bundle exec rails s -p 3000 -b '0.0.0.0'

  db:
    image: mysql:5.7
    volumes:
      - mysql_data:/var/lib/mysql/
    environment:
      MYSQL_ROOT_PASSWORD: password
    ports:
      - "3306:3306"

volumes:
  mysql_data:
  es_data:

Dockerfile

FROM ruby:2.7.2

RUN apt-get update -qq && apt-get -y install \
    build-essential \
    libpq-dev \
    nodejs

RUN mkdir /app

COPY Gemfile /app

WORKDIR /app

RUN gem install bundler && bundle install

Gemfile

この Gemfile はサンプルアプリケーション環境に Rails をインストールする為だけに利用され、rails new する際に上書きされます。

# frozen_string_literal: true

source "https://rubygems.org"

git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }

gem 'rails', '~> 6.0.4', '>= 6.0.4.6'

apm/apm-server.yml

このファイルが Elastic APM サーバーの設定ファイルです。

apm-server:
  host: "0.0.0.0:8200"


  kibana:
    enabled: true
    host: kibana:5601

  rum:
    enabled: true

output:
  elasticsearch:
    hosts: ["elasticsearch:9200"]

setup:
  kibana:
    host: kibana:5601

  template:
    settings:
      index:
        number_of_replicas: 0

database.yml.patch

database.yml の設定内容を更新する為のパッチファイルです。

--- config/database.yml.bk      2022-03-06 11:53:00.000000000 +0900
+++ config/database.yml 2022-03-06 11:53:12.000000000 +0900
@@ -14,8 +14,8 @@
   encoding: utf8mb4
   pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
   username: root
-  password:
-  host: localhost
+  password: password
+  host: db

 development:
   <<: *default

run-test.sh

起動したサンプルアプリケーションにリクエストを投げまくるテスト用シェルスクリプトです。

#!/bin/bash
while true
do
  curl -s -X POST -H "Content-Type: application/json" -d '{"name": "hoge"}' http://localhost:3000/users -o /dev/null -w '%{http_code}\n'
  curl -s -X GET http://localhost:3000/users -o /dev/null -w '%{http_code}\n'
  sleep 1
done

セットアップ

ファイル構成

初期段階 (リポジトリgit clone した段階) では、以下のようなファイル構成になっています。

$ tree .
.
├── Dockerfile
├── apm
│   └── apm-server.yml
├── database.yml.patch
├── docker-compose.yml
└── run-test.sh

1 directory, 5 files

Rails がインストールされているコンテナイメージを作成

$ docker-compose build --no-cache

Rails 環境を API モードで作成 (DB は MySQL)

$ docker-compose run api rails new . --force --database=mysql --api

Elastic APM の gem を追加

$ echo "gem 'elastic-apm'" >> Gemfile

もう一回、Rails コンテナイメージを作成

$ docker-compose build --no-cache

scaffold

$ docker-compose run --rm api rails generate scaffold User name:string

database.yml を設定

$ cd config
$ patch < ../database.yml.patch
$ cd ../

データベース作成、マイグレーション

$ docker-compose run --rm api rails db:create
$ docker-compose run --rm api rails db:migrate

全部のコンテナを起動

$ docker-compose up -d

正常に全てのコンテナが起動すると、下図のように 5 つのコンテナが起動している状態になると思います。

$ docker-compose ps
               Name                              Command               State                          Ports
----------------------------------------------------------------------------------------------------------------------------------
elastic-apm-sandbox_api_1             bundle exec rails s -p 300 ...   Up      0.0.0.0:3000->3000/tcp,:::3000->3000/tcp
elastic-apm-sandbox_apm_1             /usr/local/bin/docker-entr ...   Up      0.0.0.0:8200->8200/tcp,:::8200->8200/tcp
elastic-apm-sandbox_db_1              docker-entrypoint.sh mysqld      Up      0.0.0.0:3306->3306/tcp,:::3306->3306/tcp, 33060/tcp
elastic-apm-sandbox_elasticsearch_1   /tini -- /usr/local/bin/do ...   Up      0.0.0.0:9200->9200/tcp,:::9200->9200/tcp, 9300/tcp
elastic-apm-sandbox_kibana_1          /usr/local/bin/dumb-init - ...   Up      0.0.0.0:5601->5601/tcp,:::5601->5601/tcp

run-test.sh を実行

$ ./run-test.sh

Try! Elastic APM

Kibana にアクセス

コンテナが正常に起動した後、ブラウザで、以下の URL にアクセスします。

http://localhost:5601

APM メニューにアクセス

下図の APM をクリックします。

f:id:inokara:20220313185850p:plain

Services

f:id:inokara:20220313185903p:plain

NameApp をクリックします。

Transactions

f:id:inokara:20220313185917p:plain

UsersController#create のリンクをクリックすると、下図のようにリクエストをトレース (API コールやデータベースのクエリ等) をドリルダウンして確認することが出来ます。

f:id:inokara:20220313185932p:plain

15 分くらい触ってみた感想

  • New Relic ほど色々出来るわけでは無さそう
  • ひとまず、アプリケーション内部のレイテンシー等の最低限の機能は提供されていそう
  • シュッと Docker で試せるのは良い