Amazon Web Service の EC2 Container Registory (ECR) は、フルマネージドな Docker コンテナリポジトリです。プライベートな Docker イメージをプッシュし、EC2にデプロイすることができます。
今回の構成
- AWS EC2 Container Registory (ECR)
- AWS ElasticBeanstalk
- Docker
- Python3
- Django1.10
- uwsgi
- nginx
- supervisor
- Fabric
手元で、Python3 + Django の Docker イメージを作り、EC2 Container Registory (ECR) にプッシュし、ElasticBeanstalk (EB) でデプロイするまで書きます。
サンプルコード
こちらです。 https://github.com/ytyng/aws-eb-docker-django-skeleton
Fabric の準備
fabric は必須ではありませんが、私はコマンドをすぐ忘れてしまうため fabric のコマンド化してあります。
とはいえ、サーバに SSH でデプロイするわけではないので、fabric の本来の使い方ではないですね。(make や invoke なんかで良さそうです)
fabric は、あらかじめローカル環境にインストールしておく必要があります。
おそらく、Python3 では動作しないため、ローカルの Python2 環境に
インストールする必要があります。
$ python
Python 2.7.10
...
$ sudo pip install fabric
Dockerイメージのビルド
$ fab build
(もしくは $ docker build -t aws-eb-docker-django-skeleton )
FROM ubuntu:16.04
MAINTAINER ytyng
RUN apt-get update && apt-get install -y \
python3 \
python3-pip \
python3-dev \
python3-setuptools \
nginx \
supervisor \
&& rm -rf /var/lib/apt/lists/*
# for pil
# apt-get install libjpeg-dev
# RUN ln -s /usr/lib/x86_64-linux-gnu/libjpeg.so /usr/lib/libjpeg.so
# for ipython
# apt-get install lib32ncurses5-dev
# set locale
RUN locale-gen en_US.UTF-8
ENV LANG en_US.UTF-8
ENV LANGUAGE en_US:en
ENV LC_ALL en_US.UTF-8
# Python packages
COPY requirements/base.txt /tmp/requirements/base.txt
COPY requirements/production.txt /tmp/requirements/production.txt
RUN pip3 install -r /tmp/requirements/base.txt
RUN pip3 install -r /tmp/requirements/production.txt
# setup all the configfiles
RUN echo "daemon off;" >> /etc/nginx/nginx.conf
COPY conf/nginx-app.conf /etc/nginx/sites-available/default
COPY conf/supervisor-app.conf /etc/supervisor/conf.d/
RUN mkdir /var/log/django
COPY . /var/django/aws-eb-docker-django-skeleton
EXPOSE 80
EXPOSE 443
CMD ["supervisord", "-n"]
DBマイグレーション
$ fab manage:migrate
↑コマンドが何をしているかは fabfile を見てみてください
サーバ起動
$ fab up
(ポート 80, 443 をバインドします)
version: '2'
services:
aws-eb-docker-django-skeleton:
build: .
image: aws-eb-docker-django-skeleton
container_name: aws-eb-docker-django-skeleton
ports:
- 80:80
- 443:443
volumes:
- /etc/localtime:/etc/localtime:ro
- .:/var/django/aws-eb-docker-django-skeleton
environment:
- UWSGI_PROCESSES=1
- UWSGI_THREADS=1
- APP_NAME=aws-eb-docker-django-skeleton
- DJANGO_APP_NAME=aws_eb_docker_django_skeleton
- DJANGO_SETTINGS_MODULE=aws_eb_docker_django_skeleton.settings.local
$ docker-machine ls
でIPアドレスを調べ(例: 192.168.99.100 )、
ブラウザで開くと起動ページが見れます
$ open "http://192.168.99.100/"
Docker リポジトリを、AWS EC2コンテナサービス (ECS) に登録する
プライベートリポジトリとして登録できます。
1. ローカルPCの AWS CLI を設定 (既に行っていれば不要)
1-1. IAM より、ローカルコンピュータに保存するログインクレデンシャルを作っておきます。
既に作ってある場合は不要です。
ユーザー → 新規ユーザーの作成
ユーザー名 適当に (例: aws-cli )
ユーザーのセキュリティ認証情報を表示 をクリックし、アクセスキー ID と シークレットアクセスキー を保存しておく。
もしくは「認証情報のダウンロード」を押して、CSVを保存しておく。
閉じる をクリック
作成したユーザーを選択し、「ポリシーのアタッチ」
AmazonEC2ContainerRegistryFullAccess をアタッチしておきましょう
1-2. aws cli のインストール
$ sudo pip install awscli --upgrade --ignore-installed six
1-3. aws を設定
$ aws configure
さきほどのクレデンシャル情報を入力しておく
AWS Access Key ID [None]: AK................
AWS Secret Access Key [None]: ********************************
Default region name [None]: ap-northeast-1
Default output format [None]:
2. AWS EC2 コンテナリポジトリの設定とイメージのプッシュ
2-1. AWS コンソールの ECSページを表示
初回起動時、チェックボックスが出ます。
Store container images securely with Amazon ECR にチェックON して Continue。
Repository name にリポジトリ名を入力して、Next step。
すると、コンソールでの手順が表示されます。
2-2. ローカルでコンテナ登録コマンド実行
表示されたコマンドにそって
$ aws ecr get-login --region ap-northeast-1
ターミナルから入力すべきコマンドが表示されます。つまり、やるべきことは
$ $(aws ecr get-login --region ap-northeast-1)
です。
$ $(aws ecr get-login --region ap-northeast-1)
Flag --email has been deprecated, will be removed in 1.13.
Login Succeeded
fab のコマンドも用意してあります。 $ fab login_ecr
引き続き、AWSのページの手順に沿って続けます。
$ docker tag aws-eb-docker-django-skeleton:latest 000000000000.dkr.ecr.ap-northeast-1.amazonaws.com/aws-eb-docker-django-skeleton:latest
$ docker push 000000000000.dkr.ecr.ap-northeast-1.amazonaws.com/aws-eb-docker-django-skeleton:latest
fab のコマンドも用意してあります $ fab push
3. プッシュしたイメージから ElasticBeanstalk でインスタンスを作成
3-1. EBを作成
プラットフォームの選択 は、Multi-container Docker にして、「今すぐ起動」
(※起動する Docker コンテナは1つですが、単一Docker コンテナの設定ファイルと互換性が無いため、あとからコンテナを増やしたい場合等に困ります。マルチコンテナDockerで全く問題無いでしょう。(メモリ設定が必須で少し面倒なぐらい?))
そしたら、「初めての Elastic Beanstalk アプリケーション」という変なアプリケーションが
出来たので、これは無視して右上の「新しいアプリケーションの作成」をクリック
アプリケーション名は適当に、例: aws-eb-docker-django-skeleton
→ 次へ → ウェブサーバーの作成 →
プラットフォームの選択: Multi-container Docker
環境タイプ: 単一インスタンス
→ 次へ
送信元: 独自のアップロード
今回は、手作業で Json ファイルをアップロードします。
本来は、S3経由でコマンドでアップロードなどした方が良いと思うのですが、
ここの ベストプラクティスはまだ確立できていません。(ebコマンドでできるか等もまだ不明…)
EC2コンテナサービス (ECS) を使う場合、Dockerrun.aws.json だけアップロードすれば良いです。
{
"AWSEBDockerrunVersion": 2,
"containerDefinitions": [
{
"name": "aws-eb-docker-django-skeleton",
"image": "000000000000.dkr.ecr.ap-northeast-1.amazonaws.com/aws-eb-docker-django-skeleton:latest",
"essential": true,
"environment": [
{
"name": "UWSGI_PROCESSES",
"value": "2"
},
{
"name": "UWSGI_THREADS",
"value": "2"
},
{
"name": "APP_NAME",
"value": "aws-eb-docker-django-skeleton"
},
{
"name": "DJANGO_APP_NAME",
"value": "aws_eb_docker_django_skeleton"
},
{
"name": "DJANGO_SETTINGS_MODULE",
"value": "aws_eb_docker_django_skeleton.settings.production"
}
],
"portMappings": [
{
"hostPort": 80,
"containerPort": 80
},
{
"hostPort": 443,
"containerPort": 443
}
],
"memory": 256,
"memoryReservation": 128
}
]
}
image の箇所を修正した json ファイルを、「独自のアップロード」のファイルに指定します。
環境名、環境URL は、例: aws-eb-docker-django-skeleton を入力
その他のリソース は、今回は使わないのでチェック無しで「次へ」
構成の詳細は適当に。今回はテストなので t1.micro で充分です
環境タグ も不要なので入力せずに「次へ」
アクセス制限 も、そのままで『次へ」
内容がプレビューされますので、「起動」
しばらく待つとインスタンスが作られるのですが、そのままでは下記のようにエラーになります。
ECS task stopped due to: Essential container in task exited. (aws-eb-docker-django-skeleton: CannotPullContainerError: AccessDeniedException: User: arn:aws:sts::000000000000:assumed-role/aws-elasticbeanstalk-ec2-role/i-00000000 is not authorized to perform: ecr:GetAuthorizationToken on resource: * status code: 400, request id: 00000000-0000-0000)
3-2. ロールにポリシーを設定
エラーの原因は、EB のロールが ECS (コンテナレジストリ) の GetAuthorizationToken の
権限が無いためです。付与しましょう。
から、aws-elasticbeanstalk-ec2-role を選択し、「ポリシーのアタッチ」→ container で検索して、
AmazonEC2ContainerRegistryReadOnly をアタッチします。
3-3. 再デプロイ
EB のアプリケーションのページの、アップロードとデプロイ → アプリケーションバージョン ページ
「最初のリリース」を選択して「デプロイ」
Environment update completed successfully. になりました。
4. ページ確認
EB には1つの URL が割り当てられます。例: aws-eb-docker-django-skeleton.ap-northeast-1.elasticbeanstalk.com
ブラウザでEBのURLにアクセスするとページが表示されます。
追記
EB でデプロイすると、遅いですしダウンタイムもあったので少し使いづらいですね。
複数台構成にしてローリングデプロイなんかで対応する必要がありそうですが、 uwsgi や gunicorn は無停止リロードができるのでせっかくなら活用したい所です。