Elastic Beanstalkのdockerチュートリアルをやってみた所感

f:id:nakahashi_h:20171208023211p:plain ローカル環境で、dockerを構築できるようにはなったのですが、それを実際にサーバで運用する方法がわかっていませんでした。
「パン食い競争」でパンと物干し竿があっても、パンがどうやって結ばれているのかわからないような状態です。(あずまんが大王の大阪リスペクト)
f:id:nakahashi_h:20171208023100p:plain

色々調べると、次の方法が本来のやり方のような気がします。

  1. EC2にインスタンスを立てる。
  2. Dockerをインストールする。
  3. docker-compose.ymlを入れた状態のソースをデプロイする。
  4. docker-composeを実行して環境を構築する

しかし手動で構築してしまうと、操作の記録が残らないので以降構築する時に記憶頼りになるため時間がかかったり、誤って構築してしまう可能性があります。
awsでは上記のフローを設定ファイルにまとめて一括で事項できるサービスがあります。
それが、「Elastic Beanstalk」です。
今回は、Elastic Beanstalkで、Docker環境を構築するためのチュートリアルを実行した所感についてまとめます。

この記事で得られる事

  • docker-composeで作ったdockerの設定をaws上で実行する手段。
  • Elastic Beanstalkをコマンドから実行できるようにする。

参考資料

公式のチュートリアルをベースに構築しています。 Elastic Beanstalk(以下、eb)のチュートリアルおよびサンプルは複数用意されており、且つ、dockerについてもフルスタックの「単一コンテナ」と、複数のコンテナを組み合わせて使う「複数コンテナ」が用意されています。
今回は、実際に作りたい環境に近い複数コンテナの方で実行します。

完成形は公式のドキュメントにもあるhttps://github.com/awslabs/eb-docker-nginx-proxyになります。
結果だけ知りたい場合はそちらをダウンロードしてください。
また、参考資料と違うところは、デプロイ時に、awsのコントローラパネルからでなく、eb cliを使用しているところです。

ebの構築に必要なファイルを用意

プロジェクトフォルダは「eb_stady」としています。 最終的には、下記のような構成になります。

eb_stady
├── Dockerrun.aws.json
├── php-app
│   ├── index.php
│   └── static.html
└── proxy
    └── conf.d
        └── default.conf

eb用のdockerの構成ファイル用意

eb用のdocker-composeを用意します。
ebでdocker-composeのようにコンテナ同士をマウントさせるための構成ファイルを用意する場合は、「Dockerrun.aws.json」というファイルを用意してデプロイします。

Dockerrun.aws.json

{
   "AWSEBDockerrunVersion": 2,
   "volumes": [
       {
           "name": "php-app",
           "host": {
               "sourcePath": "/var/app/current/php-app"
           }
       },
       {
           "name": "nginx-proxy-conf",
           "host": {
               "sourcePath": "/var/app/current/proxy/conf.d"
           }
       }
   ],
    "containerDefinitions":  [
        {
            "name": "php-app",
            "image": "php:fpm",
            "essential": true,
            "memory": 128,
            "mountPoints": [
               {
                   "sourceVolume": "php-app",
                   "containerPath": "/var/www/html",
                   "readOnly": true
               }
            ]
        },
        {
            "name": "nginx-proxy",
            "image": "nginx",
            "essential": true,
            "memory": 128,
            "portMappings": [
                {
                    "hostPort": 80,     
                    "containerPort": 80
                }
            ],
            "links": [
                "php-app"
            ],
            "mountPoints": [
                {
                   "sourceVolume": "php-app",
                   "containerPath": "/var/www/html",
                   "readOnly": true
                },
                {
                   "sourceVolume": "nginx-proxy-conf",
                   "containerPath": "/etc/nginx/conf.d",
                   "readOnly": true
                },
                {
                   "sourceVolume": "awseb-logs-nginx-proxy",
                   "containerPath": "awseb-logs-nginx-proxy"
                }
            ]
        }

    ]
}

docker-composeでserviceに当たる部分が、「containerDefinitions」に当たります。
ただ、eb特有の事も書いているので、詳しい指定の仕方はElastic Container Service(以下、ecs)のドキュメントを参照してください。

また、クライアント(ローカル)側のソースは、「/var/app/current/」にデプロイされます。
そのため、volumes->host->sourcePathでソース場所を定義し、mountPointsのcontainerPathにマウントさせます。
そこの詳細な説明はecsのタスクでのデータボリュームの使用を参照してください。

出力するファイルを用意

出力が確認できるものであればどのような記述でも構いません。
(チュートリアルに習って)下記のファイルを作成します。

php-app\index.php

<h1>Hello World!!!</h1>
<h3>PHP Version <pre><?= phpversion()?></pre></h3>

php-app\static.html

<h1>Hello World!</h1>
<h3>This is a static HTML page.</h3>

nginxのconfファイルを用意する

webサーバーのルートパスと、php-fpmの設定をした状態のconfファイルを作成します。

proxy/conf.d/default.conf

server {
    listen 80;
    server_name localhost;
    root /var/www/html;

    index index.php;

    location ~ [^/]\.php(/|$) {
        fastcgi_split_path_info ^(.+?\.php)(/.*)$;
        if (!-f $document_root$fastcgi_script_name) {
            return 404;
        }

        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_path_info;
        fastcgi_param PATH_TRANSLATED $document_root$fastcgi_path_info;

        fastcgi_pass php-app:9000;
        fastcgi_index index.php;
    }
}

プロジェクトフォルダーでeb cliを使うための設定

ebコマンドでデプロイできるように、プロジェクトフォルダーの設定を行います。
なお、既にアクセスキーの設定は済んでいるので割愛していますが、まだ設定していない場合はドキュメントを参考に設定してください。

$ cd (プロジェクトディレクトリ)
$ eb init

Select a default region
1) us-east-1 : US East (N. Virginia)
2) us-west-1 : US West (N. California)
3) us-west-2 : US West (Oregon)
4) eu-west-1 : EU (Ireland)
5) eu-central-1 : EU (Frankfurt)
6) ap-south-1 : Asia Pacific (Mumbai)
7) ap-southeast-1 : Asia Pacific (Singapore)
8) ap-southeast-2 : Asia Pacific (Sydney)
9) ap-northeast-1 : Asia Pacific (Tokyo)
10) ap-northeast-2 : Asia Pacific (Seoul)
11) sa-east-1 : South America (Sao Paulo)
12) cn-north-1 : China (Beijing)
13) us-east-2 : US East (Ohio)
14) ca-central-1 : Canada (Central)
15) eu-west-2 : EU (London)

(default is 3): 9

Enter Application Name
(default is "eb-stady"): 
Application eb-stady has been created.

It appears you are using Multi-container Docker. Is this correct?
(Y/n): Y

Select a platform version.
1) Multi-container Docker 17.03.2-ce (Generic)
2) Multi-container Docker 1.6.2 (Generic)
(default is 1): 1
Note: Elastic Beanstalk now supports AWS CodeCommit; a fully-managed source control service. To learn more, see Docs: https://aws.amazon.com/codecommit/
Do you wish to continue with CodeCommit? (y/N) (default is n):
Do you want to set up SSH for your instances?
(Y/n): Y

Select a keypair.
(SSH接続する為のキーペアを選択する)

アプリケーションに紐づく環境構築。

上記でアプリケーションの作成ができたので、紐づく環境(Environment)を作成します。

$ cd (プロジェクトディレクトリ)
$ eb create
WARNING: The Multi-container Docker platform requires additional ECS permissi
ons. Add the permissions to the aws-elasticbeanstalk-ec2-role or use your own
 instance profile by typing "-ip {profile-name}".
For more information see: https://docs.aws.amazon.com/elasticbeanstalk/latest
/dg/create_deploy_docker_ecs.html#create_deploy_docker_ecs_role
Enter Environment Name
(default is eb-stady-dev):
Enter DNS CNAME prefix
(default is eb-stady-dev):


Select a load balancer type
1) classic
2) application
3) network
(default is 1): 2

実行すると、.elasticbeanstalk/config.ymlというファイルが自動生成されます。

ebにアプリをデプロイする。

次のコマンドを打って、アプリをデプロイします。
デプロイする事で、ebのアプリと紐づく環境のリポジトリが作られ、プロジェクトディレクトリのソースアップロードされます。

$ cd (プロジェクトディレクトリ)
$ eb create

実行後の様子

ebのコンソールを開くと、アプリケーションが作成されていることがわかります。 f:id:nakahashi_h:20171208023053p:plain

作成した環境の押下すると、環境の状況が確認できます。
f:id:nakahashi_h:20171208023049p:plain

デプロイすると、dockerの設定まで終わった状態なので、右上のURLを押下するとブラウザ経由で表示確認できます。

作成したアプリケーションに変更分をデプロイする。

Dockerrun.aws.jsonを書き換えたり、ソースを修正した場合は、再度デプロイが必要になります。
ソースを変更してそれを反映したい場合は、次のコマンドで再度デプロイできます。

$ eb deploy

デプロイ時の注意

Gitでソース管理している場合は、未コミット分はデプロイしないようなので、コミットした状態にしてください。

ERROR: CommandError - git could not find the HEAD; most likely because there
are no commits present

まとめ

Elastic Beanstalkを使うと、Elastic Container Serviceの、クラスタ設定まで自動でしてくれるので作業がかなり楽になります。
vpcを用意して、リージョンが違うサブネットを用意して、ロードバランサーvpcの中に入れて…と知識が乏しい私にはハードルが高いのでそこを自動的にやってくれるのはありがたいです。   (挑戦したものの、まだ動かないので不完全燃焼ではありますが。)

ただ、実際は、docker-composeだけで環境を作るわけではなく、各コンテナのDockerfileをビルドして作るのでそこは引き続き調査が必要です。
それを知るためには、Elastic Container Serviceは避けては通れなさそうな気はしています。

余談

amazonが公式で、AWSのトレーニングを出しているのですね… (もしかしたら、この数週間は無駄だったかも) https://www.aws.training/?src=training

これにも挑戦してみたいと思います。