DockerHubのRuby Alpineで作るheadless chrome環境

headless chromeとSelenium WebDriverを使いたいと思ったときすぐ使えるような環境を作る。
Debian環境よりも簡単にインストールすることができたのでAlpine Linuxを使う。

Dockerfile

FROM ruby:2.6.4-alpine3.10

RUN apk add -U chromium chromium-chromedriver

これだけでOK。あとはgemをインストールしてオプションを渡して上げればすぐ使える。
Alpine Linuxのパッケージマネージャapkについてはこちらも要チェック

require 'selenium-webdriver'                                                                                                                                                                            

options = Selenium::WebDriver::Chrome::Options.new
options.add_argument("--no-sandbox")
options.add_argument("--headless")

session = Selenium::WebDriver.for :chrome, options: options

スクリーンショットなど、日本語フォントが必要になった際はGoogle Noto Fontsをインストールすると良い。

Dockerfileに追記

RUN mkdir /noto
ADD https://noto-website.storage.googleapis.com/pkgs/NotoSansCJKjp-hinted.zip /noto
WORKDIR /noto
RUN unzip NotoSansCJKjp-hinted.zip && \
    mkdir -p /usr/share/fonts/noto && \
    cp *.otf /usr/share/fonts/noto && \
    chmod 644 -R /usr/share/fonts/noto/ && \
    fc-cache -fv

参考リンク

Docker ComposeでRailsのアプリケーションログをFluentdでElasticsearchに送信する

過去の記事

前々回

前回


実現したいこと

Nginxと同じようにRailsのアプリケーションログもKibanaで参照できるようにしたい。
引き続き、過去の記事で使用した環境に変更を加えていくのでdiffを記載していく。

Rails

参考

基本的には参考サイトの通りやれば実現可能。
ただ、act-fluent-logger-railsに関してリリースされている最新の0.5.0ではRails6に対応していない。
Githubを確認したところmasterブランチには修正が適応されていたのでGemfileでGithubを指定すれば可能。

Gemfile
--- a/Gemfile
+++ b/Gemfile
@@ -47,3 +47,6 @@ end

 # Windows does not include zoneinfo files, so bundle the tzinfo-data gem
 gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]
+
+gem 'act-fluent-logger-rails', git: 'https://github.com/actindi/act-fluent-logger-rails.git'
+gem 'lograge'

Gemfileを更新したのでdocker-compose build webを行っておく。

config/application.rb
--- a/config/application.rb
+++ b/config/application.rb
@@ -15,5 +15,9 @@ module Myapp
     # Application configuration can go into files in config/initializers
     # -- all .rb files in that directory are automatically loaded after loading
     # the framework and any gems in your application.
+    config.log_level = :info
+    config.logger = ActFluentLoggerRails::Logger.new
+    config.lograge.enabled = true
+    config.lograge.formatter = Lograge::Formatters::Json.new
   end
 end
config/fluent-logger.yml

ファイルを新規に作成。ひとまずdevelopmentのhostのみ設定しておく。

development:
  fluent_host:   fluentd
  fluent_port:   24224
  tag:           'rails'
  messages_type: 'string'

test:
  fluent_host:   '127.0.0.1'
  fluent_port:   24224
  tag:           'rails'
  messages_type: 'string'

production:
  fluent_host:   '127.0.0.1'
  fluent_port:   24224
  tag:           'rails'
  messages_type: 'string'

Fluentd

fluent.conf

ひとまず、Nginxの設定をほぼコピペで設定。

--- a/fluentd/fluent.conf
+++ b/fluentd/fluent.conf
@@ -14,3 +14,13 @@
   logstash_format true
   logstash_prefix nginx.access
 </match>
+
+<match rails>
+  @type elasticsearch
+  host elasticsearch
+  buffer_type memory
+  port 9200
+  type_name rails
+  logstash_format true
+  logstash_prefix rails.access
+</match>

この状態で、localhostにアクセスをしてKibanaでCreate index patternをするとrailsのログがきているはず。
f:id:arcright:20190930232653p:plain

[asin:429710461X:detail]

Docker LoggingにFluentdを使いforwardでNginxのログを送信する

過去の記事

実現したいこと

以前、NginxのログをFluentdを用いてElasticsearchに送信する際は、アクセスログをデータボリュームに書き出しtailで読み込んでElasticsearchに送信する方法で実現していた。
その際、オフィシャルのNginxコンテナのアクセスログの仕様について触れた。

  • docker container logsやdocker-compose upをフォアグラウンドで実行していると見ることのできるログに、各コンテナで起きたログを表示するには標準出力、標準エラー出力に内容を書く必要がある。
  • Nginxはアクセスログをログファイルに書きつつ標準出力に書き出す方法がないので、アクセスログを標準出力にシンボリックリンクすることで実現している。
  • そのため/var/log/nginx/access.logにいくらログを書いてもコンテナ内にログは残らなくなっている。
https://chulip.org/entry/2019/08/18/233205

上記仕様を回避するため、ログファイルをわざわざ別名で書き出すようにする必要があった。

しかし、そもそもデフォルトで標準出力にアクセスログが流れてくるのであればそれをそのままElasticsearchに渡してやればよいのでは?
そうすれば、ログファイルに別名を付ける必要もないし、ログを読み込むためだけにデータボリュームを用意する必要もない。

そこで、Docker Loggingを使用してNginxコンテナのログをFluentdに渡してそのままElasticsearchに送信できるようにする。

なお、過去の記事で使用した環境に変更を加えていくのでdiffを記載していく。

Fluentd

参考
--- a/fluentd/fluent.conf
+++ b/fluentd/fluent.conf
@@ -1,9 +1,7 @@
 <source>
-  @type tail
-  format ltsv
-  path /var/log/nginx/myapp_access.log
-  tag nginx
-  pos_file /var/log/nginx/myapp_access.log.pos
+  @type forward
+  port 24224
+  bind 0.0.0.0
 </source>
 
 <match nginx>

typeをforwardに変更。

Nginx

--- a/nginx.conf
+++ b/nginx.conf
@@ -24,8 +24,8 @@ server {
   listen 80;
   server_name localhost;
 
-  access_log /var/log/nginx/myapp_access.log ltsv;
-  error_log  /var/log/nginx/myapp_error.log;
+  access_log /var/log/nginx/access.log ltsv;
+  error_log  /var/log/nginx/error.log;
 
   root /myapp/public;

ログファイルのファイル名を変更して標準出力、標準エラー出力にアクセスログが出力されるように。

docker-compose.yml

参考
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -26,11 +26,16 @@ services:
     volumes:
       - .:/myapp
       - ./nginx.conf:/etc/nginx/conf.d/default.conf
-      - http-log:/var/log/nginx
     ports:
       - 80:80
     depends_on:
       - web
+      - fluentd
+    logging:
+      driver: fluentd
+      options:
+        tag: "nginx"
+        fluentd-async-connect: "true"
   elasticsearch:
     image: elasticsearch:7.3.0
     environment:
@@ -48,7 +53,6 @@ services:
   fluentd:
     build: ./fluentd
     volumes:
-      - http-log:/var/log/nginx
       - ./fluentd/fluent.conf:/fluentd/etc/fluent.conf
     ports:
       - 24224:24224
@@ -57,4 +61,3 @@ services:
 volumes:
   db-data:
   elastic-data:
-  http-log:

まず、loggingの設定を追加。
次に、ログファイルを参照する必要がなくなったのでログファイル用のデータボリューム関連を削除。

次に、fluentd-async-connect。
docker-compose upを行うと下記WARNINGが表示される。

WARNING: no logs are available with the 'fluentd' log driver

docker-compose.ymlのdepends_onでnginxは依存していることを記述しているが、
ただ単にコンテナの作成順序が保証されるだけで、サービスが起動するまで待ってくれるわけではない。
その為か、Nginxのコンテナ起動時にFluentdがavailableではないためWARNINGが表示される。

これは、FluentdとElasticsearchにも同様のことが言える。
Elasticsearchはコンテナ起動からサービスがavailableになるまでの時間が結構かかるのでFluendはすぐに接続することができない。

#0 Remaining retry: 14. Retry to communicate after 2 second(s).

logにもリトライをしている表示が出ていて、自分の環境だとだいたい16 secondsになるとようやく接続できている。
リトライの間隔は指数関数的に増えていく(1s,2s,4s,8s,16s)

上記の事から、Nginxコンテナ立ち上げ時にFluentdに接続できることは保証されていないので、
fluentd-async-connectをtrueにしておく。
ドキュメントによるとtrueだと、接続が確立できるまでメッセージをバッファリングしてくれるようである。

これで、docker-compose upしてlocalhostにアクセスすると、NginxのアクセスログがElasticsearchに送信されてKibanaで参照できる。
tailでアクセスログを読み込んでいた場合と異なり、containerのログなのでcontainer_idやcontainer_nameも一緒に送られる。
このあたりのフォーマットの調整は必要に応じてやればよいだろう。