LoginSignup
5
4

More than 5 years have passed since last update.

PlayframeworkアプリケーションをAWSにdockerでデプロイしてCloudWatch Logsでログ収集した話

Posted at

Playframework2.5のアプリケーションをdockerでAWS EC2にデプロイしてCloudWatch Logsでログを集約した話です。デプロイの自動化はここでは触れません。すごいまとめていうとdockerのawslogs logging driverが楽で便利だから使おうぜーってだけの話です。

dockerの1.9以上のバージョンでAmazon CloudWatch Logs logging driverを使いました。
環境は下記の通りです。

環境

  • Playframework 2.5
  • Amazon Linux
  • Java 1.8 (EC2ではopenjdk1.8を利用)
  • docker 1.12.6

手順

  1. 本番用のlogbackの設定
  2. playframeworkでdockerのビルド
  3. CloudWatch Logsの設定
  4. EC2インスタンスでアプリケーション起動

1. 本番用のlogbackの設定

dockerのロギングドライバーはdockerコンテナ内の標準出力・エラー出力の内容をハンドルしてくれるので、playframeworkのアプリケーションログをファイルに出力しないですべてdocker内のコンソールに出力するようにします。

logback-production.xmlを用意して下記のようにコンソールログだけにします。SQLのログもオフにしています。

logback-production.xml
<!-- https://www.playframework.com/documentation/latest/SettingsLogger -->
<configuration>

  <conversionRule conversionWord="coloredLevel" converterClass="play.api.libs.logback.ColoredLevel" />

  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
      <pattern>%coloredLevel %logger{15} - %message%n%xException{10}</pattern>
    </encoder>
  </appender>

  <appender name="ASYNCSTDOUT" class="ch.qos.logback.classic.AsyncAppender">
    <appender-ref ref="STDOUT" />
  </appender>

  <logger name="play" level="INFO" />
  <logger name="application" level="INFO" />

  <!-- Off these ones as they are annoying, and anyway we manage configuration ourselves -->
  <logger name="com.avaje.ebean.config.PropertyMapLoader" level="OFF" />
  <logger name="com.avaje.ebeaninternal.server.core.XmlConfigLoader" level="OFF" />
  <logger name="com.avaje.ebeaninternal.server.lib.BackgroundThread" level="OFF" />
  <logger name="com.gargoylesoftware.htmlunit.javascript" level="OFF" />

  <root level="INFO">
    <appender-ref ref="ASYNCSTDOUT" />
  </root>

</configuration>

2. playframeworkでdockerのビルド

build.sbtにdockerビルド用の設定を下記のように追記します。Dockefileの内容を記述できます。ここではOracke Java8のdockerイメージを利用しています。

build.sbt
//
// docker build
//
enablePlugins(DockerPlugin)

import com.typesafe.sbt.packager.docker.{ExecCmd, Cmd}

dockerExposedPorts in Docker := Seq(9000)
dockerCommands := Seq(
  Cmd("FROM","nimmis/java:14.04-oracle-8-jdk"),

  Cmd("MAINTAINER","MychaelStyle"),
  Cmd("EXPOSE","9000"),

  Cmd("RUN","apt-get -y upgrade && apt-get -y update"),
  Cmd("RUN","apt-get -y install language-pack-ja ntp sysv-rc-conf"),
  Cmd("RUN","update-locale LANG=ja_JP.UTF-8"),

  Cmd("ADD","stage /"),
  Cmd("WORKDIR","/opt/docker"),
  Cmd("RUN","[\"chown\", \"-R\", \"daemon\", \".\"]"),
  Cmd("RUN","[\"chmod\", \"+x\", \"bin/MyApp\"]"),

  Cmd("USER","daemon"),
  Cmd("ENTRYPOINT","[\"bin/MyApp\", "
    +" \"-Dplay.cripto.secret=\\\"your secret!!\\\"\","
    +" \"-Dlogger.resource=logback-prod.xml\","
    +" \"-Dconfig.resource=production.conf\","
    +" \"-J-Xms512m\", \"-J-Xmx4096m\", \"-J-server\""
    +"]"),
  ExecCmd("CMD")
)

試しにビルドしてみます。

./bin/activator docker:stage

ビルドすると[プロジェクトフォルダ]/target/dockerフォルダ内に必要なファイルとDockerfileができています。フォルダに移動してdockerイメージを作成します。

cd target/docker
docker build -t MyAppImage .

イメージがビルドできたらコンテナを起動して見ます。起動に問題なければとりあえずOK

docker run -t -d -p 9000:9000 --name=MyApp MyAppImage

エラーなく起動すればOK! エラーがある場合やhttp://localhost:9000/でアクセスできない場合はdocker execなどでコンテナにログインして

3. CloudWatch Logsの設定

3.1. IAMロールでCloudWatch Logsを許可

公式のドキュメントを見ながらごにょごにょすればできます。
http://docs.aws.amazon.com/ja_jp/AmazonCloudWatch/latest/logs/QuickStartEC2Instance.html

まずはインスタンスで使う予定のロールにCloudWatchLogsのフルアクセスを許可するようにポリシーを設定します。ポリシー名はCloudWatchLogsFullAccessです。インスタンス用に新規にロールを作成する場合にもこのポリシーを含めるのを忘れないようにしましょう。

ポリシーの表示をしてみるとこんなコードになっています。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": [
        "logs:*"
      ],
      "Effect": "Allow",
      "Resource": "*"
    }
  ]
}

アタッチしたインスタンスをAmazon Linuxで起動します。使ったのは2017年2月現在でAmazon Linux AMI 2016.09.1 (HVM), SSD Volume Type - ami-56d4ad31のAMIです。最初の状態だと色々と入っていないので色々と入れました。

sudo yum groupinstall -y "Development tools"
sudo yum install -y docker java-1.8.0 awscli awslogs

最初に入るjavaが1.7なので1.8をいれてalternativesで1.8に切り替えます。

sudo alternatives --config java

There are 2 programs which provide 'java'.

  Selection    Command
-----------------------------------------------
*  1           /usr/lib/jvm/jre-1.7.0-openjdk.x86_64/bin/java
 + 2           /usr/lib/jvm/jre-1.8.0-openjdk.x86_64/bin/java

Enter to keep the current selection[+], or type selection number: 2

awslogsエージェントのために設定をします。

vim /etc/awslogs/awscli.conf

リージョンを東京に変更して試しにエージェントで/var/log/messagesを送信する設定をしてみます。設定ファイルの項目は公式のガイドにあります。
http://docs.aws.amazon.com/ja_jp/AmazonCloudWatch/latest/logs/AgentReference.html

/etc/awslogs/awscli.conf
[plugins]
cwlogs = cwlogs
[default]
region = ap-northeast-1
/etc/awslogs/awslogs.conf
[logstream1]
log_group_name = MyLogsTest
log_stream_name = {instance_id}
datetime_format = %Y-%m-%dT%H:%M:%S%z
time_zone = UTC
file = /var/log/messages
file_fingerprint_lines = 1
multi_line_start_pattern = {datetime_format}
initial_position = start_of_file
encoding = utf_8
buffer_duration = 10000
batch_count = 10000
batch_size = 1048576

エージェントを起動して見ます。

sudo service awslogs start
sudo chkconfig awslogs on

AWS CloudWatchのログの画面からロググループが作成されて閲覧できるようになっています!
さて、awslogs.confの設定とエージェントの起動手順はただのテストで、インスタンスにAWS CloudWatch Logsが使えるIAMロールが設定されて入ればdockerのコマンドだけで事足ります。ただし、dockerのあawslogs-logging-driverはロググループは自動で作ってくれないのでAWSマネジメントコンソール->CloudWatch->ログ の画面から「アクション」 -> 「ロググループの作成」でアプリケーション用のロググループを作成しておきます。ここでは画面は省略、[MyAppLogGroup]を作成したこととして進めます。

4. EC2インスタンスでアプリケーション起動

dockerhubとか使ってやったほうが楽なのでしょうがデプロイのテストのためインスタンスにログインしてgithubからpullしてビルドして稼働させるという手順でやってみます。

cd
mkdir webapps
cd webapps
github clone ...MyApp
cd MyApp
./bin/activator docker:stage

activatorでビルドできたらdockerイメージをビルドして起動します。

cd target/docker
docker build -t MyAppImage .
docker run -it -d --name MyApp -p 80:9000 \
  --log-driver=awslogs \
  --log-opt awslogs-region=ap-northeast-1 \
  --log-opt awslogs-group=MyAppLogGroup \
  --log-opt awslogs-stream=MyAppWebApplication \
  MyApp

以上でインスタンスにポート80でアクセスできるようになり、AWSの管理コンソールのCloudWatch -> ログの画面でログが閲覧できるようになりました!

5
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
4