Dockerで構築したRails環境にDatadogを導入する

最近業務でDatadogを使うようになったので勉強がてら試してみようと思います。 バージョンは以下の通りです。

まずはAPIモードでプロジェクトを作りましょう(--api を付けるとAPIモードになる)。

$ rails new datadog-test --api --database=mysql

gemsetも作成しましょう。

$ rbenv gemset create 2.6.3 datadog-test
$ echo > .rbenv-gemsets datadog-test

環境はDockerで作ります。mysqlも使いたいのでdocker-composeで合わせて作ります。 image軽量化のためにmulti stage buildにしています。

  • Dockerfile
FROM ruby:2.6.3-alpine as builder
RUN apk --update add --virtual build-dependencies \
    build-base \
    curl-dev \
    mysql-dev \
    linux-headers
RUN gem install bundler
WORKDIR /tmp
COPY Gemfile Gemfile
COPY Gemfile.lock Gemfile.lock
ENV BUNDLE_JOBS=4
RUN bundle install
RUN apk del build-dependencies

FROM ruby:2.6.3-alpine
ENV LANG ja_JP.UTF-8
RUN apk --update add \
    bash \
    mariadb-dev \
    tzdata
RUN gem install bundler

WORKDIR /tmp
COPY --from=builder /usr/local/bundle /usr/local/bundle

ENV APP_HOME /myapp
RUN mkdir -p $APP_HOME
WORKDIR $APP_HOME
COPY . $APP_HOME

# Start the main process.
CMD ["bundle", "exec", "rails", "server", "-b", "0.0.0.0"]
  • docker-compose.yml
version: '3'
services:
  db:
    image: mysql:5.7
    volumes:
      - mysql_data:/var/lib/mysql
    ports:
      - "3306:3306"
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: hi54ftyugiy3

  api:
    build: .
    ports:
      - "3000:3000"
    depends_on:
      - db
    environment:
      MYSQL_PASSWORD: hi54ftyugiy3

volumes:
  mysql_data:

config/database.yml は自動生成されたものを一部修正しています。hostで指定する値はdocker-compose.yml のmysqlのservice名です。

  • config/database.yml
default: &default
  adapter: mysql2
  encoding: utf8
  host: db
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  username: root
  password: <%= ENV.fetch("MYSQL_PASSWORD") { "root" } %>
  socket: /tmp/mysql.sock

development:
  <<: *default
  database: datadog-test_development

# Warning: The database defined as "test" will be erased and
# re-generated from your development database when you run "rake".
# Do not set this db to the same as development or production.
test:
  <<: *default
  database: datadog-test_test

バックグラウンドでコンテナを起動します。

$ docker-compose up -d --build
・・・
・・・
Successfully built 34aeb8dd5580
Successfully tagged datadog-test_api:latest
Creating datadog-test_db_1 ... done
Creating datadog-test_api_1 ... done

DBの作成を行います。

$ docker-compose run api bundle exec rails db:create
Starting datadog-test_db_1 ... done
Created database 'datadog-test_development'
Created database 'datadog-test_test'

http://localhost:3000/ にアクセスしてRailsの起動を確認します。 f:id:tottoto_toto:20190421011121p:plain

次に適当なAPIを作成します。本筋ではないのでscaffoldで作ります。

bin/rails g scaffold Book title:string

titleだけだとかっこ悪いのでmigrationファイルをいじります。

  • db/migrate/20190420163659_create_books.rb
class CreateBooks < ActiveRecord::Migration[5.2]
  def change
    create_table :books do |t|
      t.string   :title
      t.string   :author
      t.string   :publisher
      t.text     :isbn
      t.datetime :publication_date
      t.text     :description
      t.timestamps
    end
  end
end

許容するparameterも更新しておきます。

  • app/controllers/books_controller.rb
・・・
・・・
   # Only allow a trusted parameter "white list" through.
    def book_params
      params.require(:book).permit(
        :title,
        :author,
        :publisher,
        :isbn,
        :publication_date,
        :description
      )
    end

更新するためコンテナを起動し直します。

$ docker-compose up -d --build

DBの更新を適用します。

$ docker-compose run api bundle exec rails db:migrate RAILS_ENV=development
Starting datadog-test_db_1 ... done
== 20190420163659 CreateBooks: migrating ======================================
-- create_table(:books)
   -> 0.0161s
== 20190420163659 CreateBooks: migrated (0.0163s) =============================

再度コンテナを起動し直します。

$ docker-compose up -d --build

適当にデータを登録してみましょう。

$ curl -X POST \
>   http://localhost:3000/books \
>   -H 'content-type: application/json' \
>   -d '{
>       "title": "桃太郎",
>       "author": "名無し",
>       "publisher": "名無し出版",
>       "isbn": "0000-0000",
>       "publication_date": "2018-04-20",
>       "description": "昔々あるところに"
> }'
{"id":5,"title":"桃太郎","author":"名無し","publisher":"名無し出版","isbn":"0000-0000","publication_date":"2018-04-20T00:00:00.000Z","description":"昔々あるところに","created_at":"2019-04-20T17:13:52.000Z","updated_at":"2019-04-20T17:13:52.000Z"}

登録結果を確認してみます(そのままだと見にくいのでjqコマンドで整形しています)。

$ curl -X GET http://localhost:3000/books | jq
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   267    0   267    0     0  17248      0 --:--:-- --:--:-- --:--:-- 17800
[
  {
    "id": 1,
    "title": "桃太郎",
    "author": "名無し",
    "publisher": "名無し出版",
    "isbn": "0000-0000",
    "publication_date": "2018-04-20T00:00:00.000Z",
    "description": "昔々あるところに",
    "created_at": "2019-04-20T17:13:52.000Z",
    "updated_at": "2019-04-20T17:13:52.000Z"
  }
]

それではDatadogを導入していきます。ここを参考にすると良いでしょう。 docs.datadoghq.com

まずはgemのddtraceを追加します。

  • Gemfile
+ gem 'ddtrace'

docker-compose.ymlにDatadog用のコンテナを追加します。今回はログも取得したいので以下を参考にしましょう。

docs.datadoghq.com docs.datadoghq.com

  • docker-compose.yml
version: '3'
services:
  db:
    image: mysql:5.7
    volumes:
      - mysql_data:/var/lib/mysql
    ports:
      - "3306:3306"
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: hi54ftyugiy3

  api:
    build: .
    ports:
      - "3000:3000"
    depends_on:
      - db
    environment:
      MYSQL_PASSWORD: hi54ftyugiy3
+    links:
+      - dd-agent
+
+  dd-agent:
+    image: datadog/agent:latest
+    ports:
+      - 8126:8126
+    environment:
+      DD_API_KEY: <DatadogのAPI KEY>
+      DD_APM_ENABLED: "true"
+      DD_LOGS_ENABLED: "true"
+      DD_LOGS_CONFIG_CONTAINER_COLLECT_ALL: "true"
+      DD_AC_EXCLUDE: "name:datadog-agent"
+    volumes:
+      - /var/run/docker.sock:/var/run/docker.sock:ro
+      - /proc/:/host/proc/:ro
+      - /sys/fs/cgroup/:/host/sys/fs/cgroup:ro

volumes:
  mysql_data:

logを確認するため、Railsのログを出力させます。

  • Dockerfile
# Start the main process.
- CMD ["bundle", "exec", "rails", "server", "-b", "0.0.0.0"]
+ CMD bundle exec rails server -b 0.0.0.0 && tail -f log/development.log

initializerも作成します。

  • config/initializers/datadog.rb
require 'ddtrace'
Datadog.configure do |c|
  # This will activate auto-instrumentation for Rails
  c.use :rails
  c.tracer hostname: 'dd-agent',
           port: 8126
end

再度コンテナを起動し直します。

$ docker-compose up -d --build

適当なAPIを叩いて確認します。 f:id:tottoto_toto:20190422020453p:plainf:id:tottoto_toto:20190422020502p:plain

ちゃんと捕捉できていますね。試しにわざと例外を発生されたりもしましたが、独自のrender用のメソッドを追加したりもしましたが、問題なくログを取得できました。

終わってみると簡単でしたが、Dockerの設定が割と分かり難かったかなという印象です。皆さんもぜひ業務で役立ててみてください。