元営業WEBエンジニアのアプリ開発日記

営業出身のWEB系エンジニアが気になったものから作ってはメモを残してくブログ

DockerでNginx, Tomcat, MySQL環境作成

概要

今日はdockerを使ったjavaアプリ作成のためのローカル環境について書きます!
ちなみにこれから書く内容はMacBookPro × Docker18.06.0-ceで検証済したものとなります。

docker構成

作成したdocker-compose.ymlやDockerfileはこんな感じ

ディレクトリ構成

.
├── docker
│   ├── mailcatcher01
│   │   └── Dockerfile
│   ├── mysql01
│   │   ├── Dockerfile
│   │   └── config
│   │       └── charset.cnf
│   ├── nginx01
│   │   ├── Dockerfile
│   │   └── conf
│   │       └── nginx.conf
│   └── tomcat01
│       ├── Dockerfile
│       ├── conf
│       │   └── supervisord.conf
│       └── deployment
├── docker-compose.yml
└── tournament
    └── src
        ├── main
        │   ├── java
        │   └── resources
        └── test
            ├── java
            └── resources

docker-compose

基本的な書き方は公式をみて調べてもらえば書いてあるんで、あんまり書くこと無いですが、強いて言うならservlet01サービスにvolumesを指定。ローカル環境でビルドツール(gradleやmaven)により生成したwarファイルを./docker/tomcat01/deployment/以下に配置することでコンテナ内にも自動でデプロイできるようにしました。

version: '3'
services:
  web01:
    container_name: nginx01
    build: ./docker/nginx01
    image: nginx01:1.0.0
    ports:
      - "80:80"
    environment:
      TZ: "Asia/Tokyo"
    volumes:
      - ./docker/nginx01/conf:/etc/nginx/conf.d
    extra_hosts:
      - "tournament.local:127.0.0.1"
  servlet01:
    container_name: tomcat01
    build: ./docker/tomcat01
    image: tomcat01:1.0.0
    environment:
      TZ: "Asia/Tokyo"
    expose:
      - "8080"
    ports:
      - "8000:8000"
    volumes:
      - ./docker/tomcat01/deployment:/usr/local/tomcat/webapps/:rw
  db01:
    container_name: mysql01
    build: ./docker/mysql01
    image: mysql01:1.0.0
    command: >-
      /entrypoint.sh mysqld
        --slow_query_log=3
        --long_query_time=3
        --slow_query_log_file=/var/log/mysql/slow.log
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_DATABASE: tournament
      TZ: "Asia/Tokyo"
    ports:
      - "3306:3306"
    volumes:
      - data:/var/lib/mysql
  mail01:
    container_name: mailcatcher01
    build: ./docker/mailcatcher01
    image: mailcatcher01:1.0.0
    ports:
        - 1025:1025
        - 1080:1080
volumes:
  data: {}

Nginx

webサーバーにはNginxを使用。会社ではApacheしか触ったことなかったのでこっちを使ってみる。

FROM nginx:1.15.0

Nginxの設定ファイルがこんな感じ。

server {
    listen 80;
    server_name tournament.local;

    access_log /var/log/nginx/tomcat_access.log;
    error_log /var/log/nginx/tomcat_error.log;

    location / {
        proxy_set_header X-Forwarded-Host $host:$server_port;
        proxy_set_header X-Forwarded-Server $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_pass http://servlet01:8080/tournament/;
        index  index.html index.htm;
    }
}
  • 80番ポートで自分の設定したドメイン(tournament.local)をキャッチ
  • proxy_passでデプロイしたwarファイルtournament.warのコンテキストパスである/tournamentに飛ばす
  • proxy_set_headerでリバースプロキシー対策の設定

Tomcat

JbossかJettyか悩んだけどサーブレットコンテナーにはTomcatを選択。

FROM tomcat:8.0-jre8-alpine

# set server defautlt setting 
RUN apk --update add tzdata perl curl openssh openrc supervisor && \
    rm -rf /var/cache/apk/*
ENV TZ Asia/Tokyo

# access to velocity frmo jboss
ENV JAVA_OPTS="-Dspring.profiles.active=local"
ENV JPDA_ADDRESS=8000
ENV JPDA_TRANSPORT=dt_socket

# start tomcat & sshd
COPY ./conf/supervisord.conf /etc/supervisor/conf.d/supervisord.conf
CMD /usr/bin/supervisord -c /etc/supervisor/conf.d/supervisord.conf

Tomcatを起動させるだけならCMD ["catalina.sh", "run"]だけでいいんですが、先日Tomcatのアプリケーションでscpファイル転送しようとしたらこれではうまくいかなかった。。
そんなときsupervisordで複数のプロセス起動する作戦にしたらうまく行ったのでこっちの方式にしてます。

[supervisord]
nodaemon=true

[program:sshd]
command=/usr/sbin/sshd -D

[program:tomcat]
command=/usr/local/tomcat/bin/catalina.sh jpda run

ちなみにjdpaオプションをつけて起動させることでデバッグモードで実行できるようにしています。これはまた別の記事でも書くとしよー

MySQL

DBは慣れ親しんだMySQLにした

FROM mysql:5.6

# 設定ファイルを配置
# (MySQLは設定ファイルの権限が777だと読み込まない)
COPY config /etc/mysql/conf.d/
RUN chmod 644 /etc/mysql/conf.d/*

RUN apt-get update && \
    apt-get install -y locales && \
    rm -rf /var/lib/apt/lists/* && \
    echo "ja_JP.UTF-8 UTF-8" > /etc/locale.gen && \
    locale-gen ja_JP.UTF-8
ENV LC_ALL ja_JP.UTF-8

簡単な設定だけ書いておく

[mysqld]
explicit_defaults_for_timestamp = 1
character-set-server=utf8
sql_mode=NO_ENGINE_SUBSTITUTION
[mysql]
default-character-set=utf8

mailcatcher

実際にメール送信しないが送信した内容を確認したいのでブラウザでSMTPを利用したメール送信を確認できるmailcatcherを使う!

FROM yappabe/mailcatcher

docker実行

ここまでファイルが出来たらあとはコマンド叩くとコンテナが立ち上がってアプリ開発ができる。

イメージ作成&コンテナ立ち上げ

--buildオプション付けるとビルドも一緒にやってくれる。

docker-compose up -d --build
docker-compose ps

    Name                   Command               State                       Ports
-------------------------------------------------------------------------------------------------------
mailcatcher01   /run.sh                          Up      0.0.0.0:1025->1025/tcp, 0.0.0.0:1080->1080/tcp
mysql01         docker-entrypoint.sh /entr ...   Up      0.0.0.0:3306->3306/tcp
nginx01         nginx -g daemon off;             Up      0.0.0.0:80->80/tcp
tomcat01        /bin/sh -c /usr/bin/superv ...   Up      0.0.0.0:8000->8000/tcp, 8080/tcp

こんな感じでStateがUpとなるとうまくいってるはず!

warファイルをデプロイ

どこかでちゃんと動く簡単なwarファイルをゲットしてファイル名をtournament.warにして./docker/tomcat01/deployment/tournament.warに配置。

ブラウザでアクセス

http://tournament.local/にアクセスしてデプロイしたjavaアプリケーションが動作したらOK

メールの内容を確認

http://tournament.local:1080/にアクセスしてMailCatcherが表示さればOK

コンテナ終了

コンテナ終了したかったらこんな感じでコマンド叩く

docker-compose down

Name   Command   State   Ports
------------------------------

コンテナにアクセスする

Nginxのログを見る

コンテナ名(nginx01)を指定してコンテナにアクセス。アクセスログをtailでチェック

docker exec -it nginx01 bash
tail -f /var/log/nginx/tomcat_access.log

Tomcatのログを見る

コンテナ名(tomcat01)を指定してコンテナにアクセス。tomcatのログをtailでチェックしてちゃんとデプロイされたか確認

docker exec -it tomcat01 bash
tail -f /usr/local/tomcat/logs/catalina.2018-08-19.log

MySQLのデータを見る

コンテナ名(mysql01)を指定してコンテナにアクセス。mysqlコマンドでデータベースにアクセスしていろいろ操作。ユーザー名とパスワードは宜しく自分の環境で作ったものとか使用してくだされ

docker exec -it mysql01 bash
mysql -h localhost -u root -proot

まとめ

ちゃんと動くwarファイルを用意して以下部分だけみんなの環境用に設定すれば動くはず。。。

  • warファイル(sample.war)を./docker/tomcat01/deployment/に配置
  • Nginxのプロキシー先のディレクトリをtournamentからsampleに変更
  • ドメイン名を好きなものに変えてNginxのserver_nameもそれに変更

本当はこのdocker環境をAmazonECS(ElasticContainerService)に展開してそのまま本番でも動くようにしたかったが、結構壁にぶつかってしまったんでこれは時間を見つけてまた今度記事にしてみよう