こんにちは。 @makinoshi です。
トヨクモでは製品の外形監視などに、Clojureで作成したWebアプリケーションを使っています。
E2E監視に使うためにサーバー上でChrome Driverなどを動かす必要がありましたが、その環境を構成管理ツールでも、ましてや手動で構築する手間をかけたくはありません。 またその環境が正常に動作するかをローカルで確認して、そのままデプロイできれば簡単です。
そこでElastic Beanstalk Multicontainer Docker(以下、EB)とElastic Container Registry(以下、ECR)を使って構築することにしました。
Clojureのアプリケーションは1つのjarファイルにして java -jar
で実行するので、ノウハウとしてはJavaアプリケーションのデプロイと変わりません。
手順としては、ECRにコンテナをデプロイし、EBの環境を構築して設定ファイルを準備し、EBにデプロイすれば完了です。
ディレクトリ構成
まずディレクトリ構成からです。今回の記事の主旨以外のソースコード等は省略しています。
. ├── Makefile ├── docker │ ├── java │ │ ├── Dockerfile │ │ └── jar │ │ └── app.jar │ └── nginx │ ├── Dockerfile │ └── nginx.conf ├── eb │ ├── Dockerrun.aws.json
ECRにコンテナのリポジトリを作る
まずAWS ECRの管理画面で今回デプロイするコンテナのリポジトリを作ります。ECR > リポジトリの作成から作ることができます。
この例ではNginxとJavaアプリケーションの2つのコンテナが必要なので2つのリポジトリを作りました。
JavaアプリケーションのDockerfile
前述のように今回はJavaアプリケーションが動作するコンテナ上にChromeDriverが動作する環境が必要だったので、次のようなDockerfileを書きました。
FROM amazoncorretto:8 WORKDIR /app COPY jar/app.jar /app/app.jar RUN yum update -y && yum install -y \ wget \ unzip \ ipa-gothic-fonts ipa-mincho-fonts ipa-pgothic-fonts ipa-pmincho-fonts \ https://dl.google.com/linux/direct/google-chrome-stable_current_x86_64.rpm \ && yum clean all \ && rm -rf /var/cache/yum RUN wget https://chromedriver.storage.googleapis.com/75.0.3770.90/chromedriver_linux64.zip \ && unzip chromedriver_linux64.zip \ && mv chromedriver /usr/local/bin/ \ && rm chromedriver_linux64.zip EXPOSE 5000 ENTRYPOINT ["java", "-jar", "-server", "-XX:+TieredCompilation", "-Xms512m", "-Xmx512m", "/app/app.jar"]
JDKとしてAmazon Correttoの公式Dockerコンテナを使っています。
またChromeとChromeDriverのインストールではyumのキャッシュやダウンロードしたzipファイルを削除することで、極力ビルドしたコンテナサイズを小さくするようにしています。
最後の ENTRYPOINT
でJVMのオプションを渡していますが、特にメモリ設定についてはお使いのインスタンスサイズ等に合わせたものにしていただければと思います。
NginxのDockerfile
リバースプロキシとしてNginxを使います。
まず nginx.conf
は次のようになります。
user nginx; worker_processes auto; error_log /var/log/nginx/error.log warn; pid /var/run/nginx.pid; events { worker_connections 1024; } http { include /etc/nginx/mime.types; sendfile on; tcp_nopush on; upstream app_backend { server java:5000; } server { listen 80; location / { proxy_pass http://app_backend; } } }
ポイントは upstream app_backend
の設定です。後述しますが、EBに渡す設定ファイルで別のDockerコンテナをどう参照できるか設定でき、ここでは java
という名前で参照させ、またJavaのDockerfileで5000をEXPOSEしたので、 server java:5000
と設定しました。
Dockerfileはシンプルです。
FROM nginx:mainline COPY nginx.conf /etc/nginx/nginx.conf EXPOSE 80
ECRへのプッシュ方法
作ったリポジトリの詳細画面に入り、「プッシュコマンドの表示」をクリックすると、そのリポジトリにDockerイメージをプッシュする方法が表示されます。
後ほどMakefileの中でECRへのプッシュを含む、全体のデプロイ方法を紹介します。
EBの環境を構築
今回はCLIではなくマネジメントコンソールから作成しました。
環境の作成を選択し、「事前設定済みプラットフォーム」に「Multi-container Docker」を選択します。アプリケーションコードはサンプルアプリケーションのままにします。 本記事ではVPN等のネットワーク環境の構築については解説しませんが、VPNの中に入れ、さらにNAT経由で外にアクセスするようにしています。
作成が完了したら、ステータスやログを確認して、正常に環境が構築できたことを確認します。
確認できたらebcliを使ってEBの環境を参照するための設定ファイルを作ります。
$ cd eb $ eb init # 作成した環境を選択
Dockerrun.aws.json
EBに対して具体的なコンテナの設定をするのが Dockerrun.aws.json
ファイルです。
{ "AWSEBDockerrunVersion": 2, "containerDefinitions": [ { "name": "java", "image": "<ECR上のURL>", "essential": true, "memory": 1280, "logConfiguration": { "logDriver": "awslogs", "options": { "awslogs-region": "<Resion>", "awslogs-group": "<ロググループ名>" } } }, { "name": "nginx", "image": "<ECR上のURL>", "essential": true, "memory": 128, "portMappings": [ { "hostPort": 80, "containerPort": 80 } ], "links": [ "java" ], "logConfiguration": { "logDriver": "awslogs", "options": { "awslogs-region": "<Resion>", "awslogs-group": "<ロググループ名>" } } } ] }
logConfiguration
ではawslogsドライバーを使用してコンテナのログをCloudWatchLogsに集めるための設定をしています。
links
で name
を指定して参照させています。リバースプロキシするために、nginxにjavaで参照できるように設定を渡しています。
Makefileでデプロイ
最後に一連のデプロイをMakefileで単一のタスクに組み上げます。
# ClojureアプリケーションをLeiningenでビルドし、 # Dockerfileから参照できるディレクトリにJARファイルを配置する jar-build: @lein do clean, uberjar @mkdir -p docker/java/jar @cp -p target/uberjar/harvest.jar docker/java/jar/ docker-build: @cd docker/java && docker build -t <ECRのリポジトリ名> . @cd docker/nginx && docker build -t <ECRのリポジトリ名> . build: jar-build docker-build login-ecr: $(shell aws ecr get-login --no-include-email --region <Resion>) push-java-docker: docker tag <ECRのリポジトリ名>:latest <ECRのイメージURL>:latest docker push <ECRのイメージURL>:latest push-nginx-docker: docker tag <ECRのリポジトリ名>:latest <ECRのイメージURL>:latest docker push <ECRのイメージURL>:latest push-docker: login-ecr push-java-docker push-nginx-docker deploy: build push-docker @cd eb && eb deploy
JARファイルのビルド以外は、ECRのリポジトリで解説されている手順通りです。
あとは、make deploy
を実行すれば完了です。
おわりに
EBを使うことで非常に簡単にDockerをデプロイすることができました。
弊社では現在運用中のPHP製品をEB+ECRの構成に変更するプロジェクトが進行中です。
Javaアプリケーションだと本記事のようにJARファイル1つを配置して起動するだけですし、起動オプション等もENTRYPOINTで java -jar
コマンドの引数に渡すだけとかなり簡単にできますが、PHPのアプリケーションではそうはいきません。
次回以降の記事で、PHPの本番環境をDocker化するノウハウについて共有していこうと思います。
弊社では技術が好きなエンジニアを継続的に募集しています。
興味を持っていただいた方は、ページ下部の採用情報をご覧ください。