RedashをAMIから起動してみた

公式AMIからインスタンスの起動

https://redash.io/help-onpremise/setup/setting-up-redash-instance.html

から AMI を選択します。Region ap-northeast-1 の AMI リンクをクリックするとインスタンスタイプを選択する画面に遷移するので、適当なインスタンスタイプを選択します。

1年間の無料枠を使っているので無料で使える t2.micro にしました。

キーペアを設定して起動します。

アクセス設定

マネジメントコンソールからインスタンスのセキュリティーグループのインバウンドで HTTP アクセスを適切に許可します。

これでブラウザからインスタンスのIPにアクセスすればページが表示されます。

internal_server_error.png

Internal Server Error(500エラー)ですね。サービス側に問題がありそうなので確認します。

サーバ側設定

起動したインスタンスに SSH ログインします。

とりあえずサービスを再起動してみます。

$ sudo supervisorctl restart all
redash_server: stopped
redash_celery_scheduled: stopped
redash_celery: stopped
redash_celery: started
redash_server: started
redash_celery_scheduled: started

再度ブラウザをリロードしてみますが、Internal Server Error に変化はありません。

supervisord のログを確認します。

$ less /var/log/supervisor/supervisord.log

が、怪しそうなログは出ていません。Redash が使っているサービスの起動状態をひとつひとつ確認します。

PostgreSQL のプロセスを確認します。

$ ps aux | grep -i postgres
ubuntu   21547  0.0  0.0  12948   932 pts/0    S+   13:47   0:00 grep --color=auto -i postgres

見つからないので、PostgreSQL が起動していない事が原因のようです。ログを確認します。

$ less /var/log/postgresql/postgresql-9.5-main.log
2017-10-16 13:32:30 UTC [1352-1] LOG:  database system was shut down at 2017-08-13 12:39:56 UTC
2017-10-16 13:32:30 UTC [1352-2] LOG:  MultiXact member wraparound protections are now enabled
2017-10-16 13:32:30 UTC [1351-1] LOG:  database system is ready to accept connections
2017-10-16 13:32:30 UTC [1356-1] LOG:  autovacuum launcher started
2017-10-16 13:32:31 UTC [1361-1] [unknown]@[unknown] LOG:  incomplete startup packet
2017-10-16 13:34:33 UTC [1351-2] LOG:  received fast shutdown request
2017-10-16 13:34:33 UTC [1351-3] LOG:  aborting any active transactions
2017-10-16 13:34:33 UTC [1705-1] redash@redash FATAL:  terminating connection due to administrator command
2017-10-16 13:34:33 UTC [1704-1] redash@redash FATAL:  terminating connection due to administrator command
2017-10-16 13:34:33 UTC [1356-2] LOG:  autovacuum launcher shutting down
2017-10-16 13:34:34 UTC [1353-1] LOG:  shutting down
2017-10-16 13:34:34 UTC [1353-2] LOG:  database system is shut down
2017-10-16 13:34:53 UTC [19851-1] FATAL:  could not map anonymous shared memory: Cannot allocate memory
2017-10-16 13:34:53 UTC [19851-2] HINT:  This error usually means that PostgreSQL's request for a shared memory segment exceeded available memory, swap space, or huge pages. To reduce the request size (currently 148488192 bytes), reduce PostgreSQL's shared memory usage, perhaps by reducing shared_buffers or max_connections.

FATAL エラーが出てますね。その前にログの時刻が見づらいので、タイムゾーンを日本時間に変更します。

$ sudo timedatectl set-timezone Asia/Tokyo
$ date
Mon Oct 16 22:53:17 JST 2017

JST に変わりました。

先ほどの PostgreSQL のエラーは割り当てられたメモリサイズが大きいというもののようです。

$ sudo vi /etc/postgresql/9.5/main/postgresql.conf

#max_connections = 100
max_connections = 50

#shared_buffers = 128MB
shared_buffers = 32MB

少ないですね。再起動します。

$ sudo /etc/init.d/postgresql restart
Restarting postgresql (via systemctl): postgresql.service.

プロセスを確認します。

$ ps aux | grep -i postgres
postgres 21785  0.0  1.5 186840 15880 ?        S    23:02   0:00 /usr/lib/postgresql/9.5/bin/postgres -D /var/lib/postgresql/9.5/main -c config_file=/etc/postgresql/9.5/main/postgresql.conf
postgres 21787  0.0  0.3 186840  3832 ?        Ss   23:02   0:00 postgres: checkpointer process
postgres 21788  0.0  0.3 186840  3832 ?        Ss   23:02   0:00 postgres: writer process
postgres 21789  0.0  0.3 186840  3832 ?        Ss   23:02   0:00 postgres: wal writer process
postgres 21790  0.0  0.6 187244  6104 ?        Ss   23:02   0:00 postgres: autovacuum launcher process
postgres 21791  0.0  0.3 148544  3128 ?        Ss   23:02   0:00 postgres: stats collector process
ubuntu   21808  0.0  0.1  12948  1092 pts/0    S+   23:02   0:00 grep --color=auto -i postgres

起動した!

ブラウザからアクセスすると。

welcome_redash.png

表示された!

Admin ユーザを登録すればとりあえず使えるようになります。

このままだとメール設定などが出来ていなので、必要であればヘルプ

https://redash.io/help/

などを参考にします。

ちなみに

最初に試した時は、次のような en_US.UTF-8 ロケールが無いというエラーが出ていました。

2017-10-09 08:38:28 UTC [2801-1] redash@redash FATAL:  database locale is incompatible with operating system
2017-10-09 08:38:28 UTC [2801-2] redash@redash DETAIL:  The database was initialized with LC_COLLATE "en_US.UTF-8",  which is not recognized by setlocale().
2017-10-09 08:38:28 UTC [2801-3] redash@redash HINT:  Recreate the database with another locale or install the missing locale.

確認すると確かに無い。

$ locale -a
C
C.UTF-8  # en_US.utf8 がない
POSIX

そのため、次のようにして en_US.UTF-8 をインストールして起動しました。

$ sudo locale-gen en_US.UTF-8
$ locale -a
C
C.UTF-8
en_US.utf8
POSIX

この記事を書くために最初から通して試してみたら en_US.utf8 ローカルが入っていて、再現しませんでした。

Issue を立てたのですが、勘違いだった可能性が高いのでそっと閉じました。

続きを読む

AWSの用語と解説

AWS(Amazon Web Services)General_AWScloud.png

インフラ系のクラウドサービスを提供しているAWSは2006年3月から始まり、現在10周年。
アメリカでは政府機関が使っているほど高いセキュリティ

サービスや機能は800個以上あり、もはや中の人も何がいつリリースされたかわからないらしい

Region(リージョン)

AWSは世界中のデータセンターのサーバーで実行されており、サービスを開始する時はリージョンを選択する
リージョンは以下の通り

リージョン
米国東部(バージニア北部) us-east-1
米国西部(オレゴン) us-west-2
米国西部(北カリフォルニア) us-west-1
欧州(アイルランド) eu-west-1
欧州(フランクフルト) eu-central-1
アジアパシフィック (シンガポール) ap-southeast-1
アジアパシフィック(東京) ap-northeast-1
アジアパシフィック (ソウル) ap-northeast-2
アジアパシフィック(シドニー) ap-southeast-2
南米 (サンパウロ) sa-east-1
中国(北京) cn-north-1

アジアパシフィックを選んでおけば問題ないが、特定のリージョンにしかないマイナーなサービスがあったりするので注意が必要

AZ(アベイラビリティゾーン)

リージョン内のデータセンターのことで、
東京リージョンだと ap-northeast-1a ap-northeast-1b ap-northeast-1c のAZがある

EC2(Elastic Compute Cloud) Compute_AmazonEC2.png

仮想サーバ

ブラウザ上で何回かクリックするだけで、簡単にインスタンスが立ち上がる
利用料金はインスタンスタイプや性能にもよるが、最低スペックで 744円/月 くらい?

RDS(Relational Database Service) Database_AmazonRDS.png

リレーショナルデータベース

Amazon Aurora  Oracle  Microsoft SQL Server  PostgreSQL  MySQL  MariaDB
からデータベースエンジンを選択可能

中でも MySQL5.6互換がある Amazon Auroraは1分あたり600万回のインサート、3000万件のセレクトが可能らしい。
下記のサイトによれば、DB性能向上が期待できそう?
http://dev.classmethod.jp/cloud/aws/wordpressdb-migrate-aurora/

Redshift  Database_AmazonRedshift.png

データウェアハウス

2TBから最大1.6PBまでスケール可能でログなどのビッグデータを保存するのによく使用される
カラムナー(列指向)と呼ばれるデータ格納方式が特徴

Redshift は、PostgreSQL 8.0.2 に基づいている。
なので、PostgreSQL 9系で追加されたクエリが使えなかったりする。

ElastiCache  Database_AmazonElasticCache.png

KVSのキャッシュサービス

Memcached・Redis から選べる
Elastic Cacheではなく ElastiCache(エラスティキャッシュ) という名前なので注意が必要

S3(Simple Storage Service) Storage_AmazonS3_bucket.png

オンラインストレージサービス

bucket(フォルダ)
object(ファイル)
という名称がある

1B ~ 5TBまでのオブジェクトを書き込み・読み込み・削除が可能
バケットに容量制限はない

・SLAは99.99%
・静的webサイトのホスティングが可能

CloudFront NetworkingContentDelivery_AmazonCloudFront.png

コンテンツデリバリネットワーク(CDN)

CDNはAkamaiなどがあるが、それに比べると割高

VPC(Virtual Private Cloud) General_virtualprivatecloud.png

仮想プライベートクラウド

Amazon VPCは、AWS上に利用者が占有可能な仮想プライベートネットワークを構築するためのサービス。
このVPCの内部にIPサブネットを作成し、その中に仮想サーバーの「EC2」やデータベースサーバーの「RDS」といったAWSのリソースを配置する。

・ユーザ側で使いたいIP空間(VPC) を作成
・VPCにユーザがサブネットを切ることができる
・サブネット単位で アクセスリストが設定できる

Route53 NetworkingContentDelivery_AmazonRoute53.png

DNSサーバ

DNSは通常マスターとスレーブ構成にすることが多く、2台で構成する場合が多いが
Route53では、4つのネームサーバーで構成され、全世界にDNSサーバーを設置しているので高可用性である
米国:20   欧州:16  アジア:12  オーストラリア:2   南米:2

・SLA100% (ほんとに?)
・DNSラウンドロビンでの負荷分散が可能
料金はかなり安い。

ホストゾーン
0.50 USD(ホストゾーンごと)/月 - 最初の25のホストゾーン
0.10 USD(ホストゾーンごと)/月 - それ以上のホストゾーン

標準的クエリ
0.400 USD(100 万クエリごと) - 最初の 10 億クエリ/月
0.200 USD(100 万クエリごと) - 10 億クエリ以上/月

1つのホストゾーンで、10億クエリ行かなければ、月1ドルかからない。

IAM(Identity and Access Management) SecurityIdentityCompliance_IAM.png

ユーザーの権限を管理できるサービス

ポリシーと呼ばれる権限をユーザーにアタッチすることで、該当ユーザーの操作できる範囲を限ることができる

ポリシーは自由に設定可能で、管理者が細かく設定可能で
例えば、とある管理者が s3-readonly-userを作成し S3の閲覧だけを許可するポリシーを作成してアタッチ。など

随時追加中…

続きを読む

個人的Auroraの良い資料まとめ

ここ1ヶ月ほどAuroraの資料をかき集めていたのですが、数ヶ月後にはそのURLとか忘れてしまいそうなのでそのメモです。対象の資料はある程度まとまった情報があるものです。

公式・非公式含めオープンにされている情報ではある程度(自分では)かき集めたと思っておりますが、何か良記事が他にもあれば教えて欲しい。

(Slide)
Amazon Aurora (Blackbelt)
https://www.slideshare.net/AmazonWebServicesJapan/aws-black-belt-online-seminar-amazon-aurora

Amazon Aurora を使いこなすためのベストプラクティス
https://www.slideshare.net/AmazonWebServicesJapan/auroraamazon-aurora

re:invent2014
https://www.slideshare.net/AmazonWebServices/sdd415-new-launch-amazon-aurora-amazons-new-relational-database-engine-aws-reinvent-2014

re:invent2016
https://www.slideshare.net/AmazonWebServices/aws-reinvent-2016-deep-dive-on-amazon-aurora-dat303

Amazon Aurora Performance Assessment
(資料に出てくるMySQLに比べて最大5倍の性能は以下の条件で出たパフォーマンス)
https://d0.awsstatic.com/product-marketing/Aurora/RDS_Aurora_Performance_Assessment_Benchmarking_v1-2.pdf

Amazon Aurora (MySQL-compatible edition) Deep Dive (AWS summit tokyo 2017)
https://d0.awsstatic.com/events/jp/2017/summit/slide/D3T1-6.pdf

Announcing Amazon Aurora with PostgreSQL Compatibility
https://www.slideshare.net/AmazonWebServices/announcing-amazon-aurora-with-postgresql-compatibility-january-2017-aws-online-tech-talks

Amazon Aurora with PostgreSQL Compatibilityを評価して
https://s3-ap-northeast-1.amazonaws.com/20170705-awssolutiondays-dbday-sessiondoc/awsdbday-keynote-SRA+OSS+Inc.pdf

(white paper)
Getting Started with Amazon Aurora
https://d0.awsstatic.com/whitepapers/getting-started-with-amazon-aurora.pdf

Amazon Auroraへのデータベースの移行
https://d0.awsstatic.com/International/ja_JP/Whitepapers/Migrating%20your%20databases%20to%20Amazon%20Aurora.pdf

Best Practices for Migrating MySQL Databases to Amazon Aurora
https://d0.awsstatic.com/whitepapers/RDS/Best-Practices-for-Migrating-MySQL-Databases-to-Amazon-Aurora.pdf

Oracle Database から Aurora & Redshift に移行するための実践ガイド
https://d0.awsstatic.com/events/jp/2017/summit/slide/D3T2-2.pdf

percona社Marco Tusa氏
http://www.tusacentral.net/joomla/index.php/mysql-blogs/175-aws-aurora-benchmarking-blast-or-splash.html
https://www.percona.com/blog/2016/05/26/aws-aurora-benchmarking-part-2/

Szymon Komendera (Auroraの中の人?)
http://blog.symedia.pl/search/label/Amazon%20Aurora

(事例)
株式会社レコチョクによる Amazon Aurora 活用事例
https://aws.amazon.com/jp/solutions/case-studies/recochoku-aurora/

ゲオを支えるDB基盤の歴史と未来~OracleからAuroraへ~
https://d0.awsstatic.com/events/jp/2017/summit/slide/D2T4-5.pdf
http://dev.classmethod.jp/cloud/aws/report-db-history-and-future-from-oracle-to-aurora-geo/

(おまけ)
Amazon CTOが公開したCloud上のデーターベースとしてのAuroraに関する解説資料
http://www.allthingsdistributed.com/2017/05/amazon-aurora-design-considerations.html
Amazon Aurora: Design Considerations for High Throughput Cloud-Native Relational Databases
http://www.allthingsdistributed.com/files/p1041-verbitski.pdf

アンチAuroraが垣間見えるpercona記事
https://www.percona.com/blog/2017/08/22/mysql-high-availability-landscape-2017-adults/
The MySQL High Availability Landscape in 2017 (The Adults)

続きを読む

現在のインスタンス料金を取得する script: RDS 編

http://qiita.com/bells17/items/5326d11edc6acc4feea2
の RDS 版です

注意点として取得するデータのエンジンを Aurora に絞ってます

rds.rb
require 'json'
require 'bigdecimal'

results = {}
json_data = open(ARGV[0]) {|io| JSON.load(io) }

# product 情報を取得
json_data['products'].keys.each do |skuNo|
    product = json_data['products'][skuNo]

    if (product['productFamily'] == 'Database Instance' and
          product['attributes']['locationType'] == 'AWS Region' and
          product['attributes']['location'] == 'Asia Pacific (Tokyo)' and
          product['attributes']['databaseEngine'] == 'Amazon Aurora') # Aurora だけに絞ってます (エンジンが mysql か postgresql かは無いっぽい??)

        results[product['sku']] = {
            sku: product['sku'],
            location: product['attributes']['location'],
            instanceType: product['attributes']['instanceType'],
            instanceFamily: product['attributes']['instanceFamily'],
            vcpu: product['attributes']['vcpu'],
            physicalProcessor: product['attributes']['physicalProcessor'],
            clockSpeed: product['attributes']['clockSpeed'],
            memory: product['attributes']['memory'],
            networkPerformance: product['attributes']['networkPerformance'],
            currentGeneration: product['attributes']['currentGeneration'],
            price_unit: 'USD'
        }

    end
end


# price

# on demand
json_data['terms']['OnDemand'].keys.each do |skuNo|
    if (results[skuNo])
        results[skuNo][:price_per_hour] = Proc.new {
            skuTerm = json_data['terms']['OnDemand'][skuNo][json_data['terms']['OnDemand'][skuNo].keys[0]]
            priceInfo = skuTerm['priceDimensions'][skuTerm['priceDimensions'].keys[0]]
            BigDecimal(priceInfo['pricePerUnit']['USD']).floor(2).to_f.to_s
        }.call
        results[skuNo][:price_per_day] = (BigDecimal(results[skuNo][:price_per_hour]) * BigDecimal("24")).floor(2).to_f.to_s
        results[skuNo][:price_per_month] = (BigDecimal(results[skuNo][:price_per_day]) * BigDecimal("30")).floor(2).to_f.to_s
    end
end

## reserved 
json_data['terms']['Reserved'].keys.each do |skuNo|
    if (results[skuNo])

        plans = json_data['terms']['Reserved'][skuNo].values.select do |plan|
            plan['termAttributes']['PurchaseOption'] == "All Upfront" # "All Upfront" のものだけ取得したい
        end

        results[skuNo][:price_reserved_1year_purchased_all_upfront] = plans.find { |plan|
            plan['termAttributes']['LeaseContractLength'] == '1yr'
        }['priceDimensions'].values.find {|priceDimension|
            priceDimension['description'] == "Upfront Fee"
        }['pricePerUnit']['USD']

        results[skuNo][:price_reserved_3year_purchased_all_upfront] = plans.find { |plan|
            plan['termAttributes']['LeaseContractLength'] == '3yr'
        }['priceDimensions'].values.find {|priceDimension|
            priceDimension['description'] == "Upfront Fee"
        }['pricePerUnit']['USD']

    end
end

# sort
sorted_result = {}
results.values.each do |row|
    sorted_result[row[:currentGeneration]] ||= {}
    sorted_result[row[:currentGeneration]][row[:instanceFamily]] ||= []
    sorted_result[row[:currentGeneration]][row[:instanceFamily]].push row
end

results = []
['Yes', 'No'].each do |currentGeneration| # 現行世代のものから並べる
    next unless sorted_result[currentGeneration]
    sorted_result[currentGeneration].keys.sort.each do |instanceFamily| # インスタンスファミリー毎に並べる
        results.concat sorted_result[currentGeneration][instanceFamily].sort_by { |row| row[:price_per_hour] }
    end
end

p results.to_json

上記を保存して以下のように実行する

curl https://pricing.us-east-1.amazonaws.com/offers/v1.0/aws/AmazonRDS/current/index.json > price-AmazonRDS.json
ruby rds.rb price-AmazonRDS.json | sed -e s/^"// | sed -e s/"$// | sed -e 's/\"/"/g' | jq .

以下のような結果が取れる

[
  {
    "sku": "H7JQN46Z6VDZ3K5V",
    "location": "Asia Pacific (Tokyo)",
    "instanceType": "db.t2.small",
    "instanceFamily": "General purpose",
    "vcpu": "1",
    "physicalProcessor": "Intel Xeon Family",
    "clockSpeed": "Up to 3.3 GHz",
    "memory": "2 GiB",
    "networkPerformance": "Low to Moderate",
    "currentGeneration": "Yes",
    "price_unit": "USD",
    "price_per_hour": "0.06",
    "price_per_day": "1.44",
    "price_per_month": "43.2",
    "price_reserved_1year_purchased_all_upfront": "403",
    "price_reserved_3year_purchased_all_upfront": "776"
  },
  {
    "sku": "MK8ETWDCPSK52PEV",
    "location": "Asia Pacific (Tokyo)",
    "instanceType": "db.t2.medium",
    "instanceFamily": "General purpose",
    "vcpu": "2",
    "physicalProcessor": "Intel Xeon Family",
    "clockSpeed": "Up to 3.3 GHz",
    "memory": "4 GiB",
    "networkPerformance": "Low to Moderate",
    "currentGeneration": "Yes",
    "price_unit": "USD",
    "price_per_hour": "0.12",
    "price_per_day": "2.88",
    "price_per_month": "86.4",
    "price_reserved_1year_purchased_all_upfront": "792",
    "price_reserved_3year_purchased_all_upfront": "1530"
  },
  {
    "sku": "8Z6GS5F6NKX37Q5E",
    "location": "Asia Pacific (Tokyo)",
    "instanceType": "db.r3.large",
    "instanceFamily": "Memory optimized",
    "vcpu": "2",
    "physicalProcessor": "Intel Xeon E5-2670 v2 (Ivy Bridge)",
    "clockSpeed": "2.5 GHz",
    "memory": "15.25 GiB",
    "networkPerformance": "Moderate",
    "currentGeneration": "Yes",
    "price_unit": "USD",
    "price_per_hour": "0.35",
    "price_per_day": "8.4",
    "price_per_month": "252.0",
    "price_reserved_1year_purchased_all_upfront": "1704",
    "price_reserved_3year_purchased_all_upfront": "3433"
  },
  {
    "sku": "PQP78BGE4C2HXDQF",
    "location": "Asia Pacific (Tokyo)",
    "instanceType": "db.r3.xlarge",
    "instanceFamily": "Memory optimized",
    "vcpu": "4",
    "physicalProcessor": "Intel Xeon E5-2670 v2 (Ivy Bridge)",
    "clockSpeed": "2.5 GHz",
    "memory": "30.5 GiB",
    "networkPerformance": "Moderate",
    "currentGeneration": "Yes",
    "price_unit": "USD",
    "price_per_hour": "0.7",
    "price_per_day": "16.8",
    "price_per_month": "504.0",
    "price_reserved_1year_purchased_all_upfront": "3408",
    "price_reserved_3year_purchased_all_upfront": "6867"
  },
  {
    "sku": "2WTMTR9HDDT7AA73",
    "location": "Asia Pacific (Tokyo)",
    "instanceType": "db.r3.2xlarge",
    "instanceFamily": "Memory optimized",
    "vcpu": "8",
    "physicalProcessor": "Intel Xeon E5-2670 v2 (Ivy Bridge)",
    "clockSpeed": "2.5 GHz",
    "memory": "61 GiB",
    "networkPerformance": "High",
    "currentGeneration": "Yes",
    "price_unit": "USD",
    "price_per_hour": "1.4",
    "price_per_day": "33.6",
    "price_per_month": "1008.0",
    "price_reserved_1year_purchased_all_upfront": "6815",
    "price_reserved_3year_purchased_all_upfront": "13733"
  },
  {
    "sku": "VRNJP9SPPRH2KM8M",
    "location": "Asia Pacific (Tokyo)",
    "instanceType": "db.r3.4xlarge",
    "instanceFamily": "Memory optimized",
    "vcpu": "16",
    "physicalProcessor": "Intel Xeon E5-2670 v2 (Ivy Bridge)",
    "clockSpeed": "2.5 GHz",
    "memory": "122 GiB",
    "networkPerformance": "High",
    "currentGeneration": "Yes",
    "price_unit": "USD",
    "price_per_hour": "2.8",
    "price_per_day": "67.2",
    "price_per_month": "2016.0",
    "price_reserved_1year_purchased_all_upfront": "13631",
    "price_reserved_3year_purchased_all_upfront": "27466"
  },
  {
    "sku": "NC3BZ293ZJFBVUT5",
    "location": "Asia Pacific (Tokyo)",
    "instanceType": "db.r3.8xlarge",
    "instanceFamily": "Memory optimized",
    "vcpu": "32",
    "physicalProcessor": "Intel Xeon E5-2670 v2 (Ivy Bridge)",
    "clockSpeed": "2.5 GHz",
    "memory": "244 GiB",
    "networkPerformance": "10 Gigabit",
    "currentGeneration": "Yes",
    "price_unit": "USD",
    "price_per_hour": "5.6",
    "price_per_day": "134.4",
    "price_per_month": "4032.0",
    "price_reserved_1year_purchased_all_upfront": "27261",
    "price_reserved_3year_purchased_all_upfront": "54932"
  }
]

続きを読む

EC2にNginx + Gunicorn + SupervisorでDjangoアプリケーションをデプロイする

Nginx + Gunicorn + Supervisorの組み合わせでDjangoアプリケーションを立ち上げたので手順のメモ
今回はOSに何も入っていない状態から始めていきます

環境

OS: Amazon Linux AMI
Python: 3.6.1
Django: 1.11.4
Nginx: 1.10.3
Gunicorn: 19.7.1
Supervisor: 3.3.3

Nginxのインストール

nginxのインストール

$ sudo yum install nginx

nginx起動する

$ sudo nginx

nginx自動起動設定

$ sudo chkconfig --add nginx
$ sudo chkconfig nginx o

自動起動設定確認
以下のようになっていればok

$ chkconfig | grep nginx
nginx           0:off   1:off   2:on    3:on    4:on    5:on    6:off

http://ipアドレスにアクセスしちゃんと起動しているか確認する
以下の通りになっていればOK
スクリーンショット 2017-08-03 13.40.56.png

Python環境の構築

今回はAnacondaで構築した
こちらからPython 3.6 versionをダウンロードする
ダウンロードしたパッケージをCyberduckなどのFTPツールで/home/ec2-userにアップロードする

アップロード完了したら下記コマンドでAnacondaインストールする

$ bash Anaconda3-4.4.0-Linux-x86_64.sh

インストール完了後、Anacondaのコマンドが使えるようにPATHを通す

$ export PATH="$PATH:/home/ec2-user/anaconda3/bin"

condaのコマンドを打って確認

$ conda info -e
# conda environments:
#
root                  *  /home/ec2-user/anaconda3

良さげです

pythonも3.6になっている

$ python --version
Python 3.6.1 :: Anaconda 4.4.0 (64-bit)

Djangoプロジェクトの作成

今回は直接EC2上でプロジェクトを作成します
本来はローカルで開発したDjangoアプリケーションをgit cloneすべき
また、DBもデフォルトのSQliteを使用しますが、実際のサービスを公開するにはPostgresqlやMariaDBを使う

まずはDjangoのインストール
root環境で動かすかどうかは少し議論の分かれるところで、別に環境を作ってDjangoを動かした方がいいんじゃないか、と思ったりもしますが、とりあえず今回はroot環境でインストールしてしまいます

$ pip install django

問題なければプロジェクトを作成

$ django-admin startproject test_project

プロジェクトが作られていることを確認

$ ls -ltr
total 511032
-rw-rw-r--  1 ec2-user ec2-user 523283080 Aug  3 04:50 Anaconda3-4.4.0-Linux-x86_64.sh
drwxrwxr-x 20 ec2-user ec2-user      4096 Aug  3 04:53 anaconda3
drwxrwxr-x  3 ec2-user ec2-user      4096 Aug  3 05:05 test_project

/test_project/test_project/settings.pyのALLOW HOSTを下記の通り編集しておく

settings.py
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True

ALLOWED_HOSTS = ["サーバのIPアドレス"]

下記のコマンドでDjangoを起動
デフォルトだと127.0.0.1:8000がbindアドレスとして使用されているため、オプションで0.0.0.0:8000を追加する必要があります
また、事前にAWSのセキュリティグループで8000番ポートを解放しておく必要があります

$ cd test_project
$ python manage.py runserver 0.0.0.0:8000

そして、http://IPアドレス:8000にアクセスすると以下の通りDjangoアプリケーションにアクセスできる
スクリーンショット 2017-08-03 15.23.25.png

Gunicornのインストール

GunicornはPython製のWSGIサーバ
WSGIサーバというのはWebサーバとWebアプリケーションをつなぐサーバのこと
なので、Nginx <-> Gunicorn <-> Djangoというような構成をイメージしていただければと

まずはGunicornのインストールをやっていく

$ pip install gunicorn

インストールされたらGunicornでDjangoを起動させる

$ gunicorn test_project.wsgi --bind=0.0.0.0:8000

先程と同様、http://IPアドレス:8000にアクセスするとDjangoアプリケーションに接続できる

Nginxの設定の変更

/etc/nginx.confを以下の通り編集する

/etc/nginx.conf

〜中略〜

http {
    〜中略〜

    upstream app_server {
        server 127.0.0.1:8000 fail_timeout=0;
    }

    server {
        #以下4行はコメントアウト
        #listen       80 default_server;
        #listen       [::]:80 default_server;
        #server_name  localhost;
        #root         /usr/share/nginx/html;

        # 以下3行を追加
        listen    80;
        server_name     IPアドレス or ドメイン;
        client_max_body_size    4G;

        # Load configuration files for the default server block.
        include /etc/nginx/default.d/*.conf;

        location / {
            # 以下4行を追加
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header Host $http_host;
            proxy_redirect off;
            proxy_pass   http://app_server;
        }

    〜以下略〜

編集したら下記コマンドでnginxを再起動する

$ sudo service nginx restart
Stopping nginx:                                            [  OK  ]
Starting nginx:                                            [  OK  ]

これでNginxでのリバースプロキシの設定は完了
今回はnginx.confを直接編集したけれど、設定ファイルをどこか別のところに書いてそれを読み込ませる、という方法でもOK

その後、DjangoをGunicornで立ち上げる

$ gunicorn test_project.wsgi --bind=0.0.0.0:8000

次はhttp://IPアドレスにアクセスするとDjangoの画面が表示されるはず

Supervisorでプロセスをデーモン化する

今の状態だとGunicornのコマンドを中止したり、サーバからログアウトするとアプリケーションが停止してしまう
これを解消するためにSupervisorでGunicornのプロセスをデーモン化する

早速、Supervisorをインストール、としたいところだけれど、SupervisorはPython2系でしか動作しない
そのためAnacondaでPython2系の仮想環境を構築し、その環境にSupervisorをインストールしていく

まずは下記コマンドでSupervisor用のPython2系の仮想環境を作る

$ conda create -n supervisor python=2.7

python2系の環境に切り替えてpipでsupervisorをインストール

$ source activate supervisor
$ pip install supervisor

問題なくインストールできたら、supervisorの設定ファイルを作成し、それを/etc配下に配置する

$ echo_supervisord_conf > supervisord.conf
$ sudo mv supervisord.conf /etc

次にsupervisorの設定を行うため、supervisord.confを下記の通り編集

supervisord.conf
〜中略〜
[supervisord]
logfile=/var/log/supervisord.log ; ログの場所を変更
;logfile=/tmp/supervisord.log ; main log file; default $CWD/supervisord.log #コメントアウト
logfile_maxbytes=50MB        ; max main logfile bytes b4 rotation; default 50MB
logfile_backups=10           ; # of main logfile backups; 0 means none, default 10
loglevel=info                ; log level; default info; others: debug,warn,trace
pidfile=/var/run/supervisord.pid ; 追記
;pidfile=/tmp/supervisord.pid ; supervisord pidfile; default supervisord.pid #コメントアウト

〜中略〜
# includeはコメントアウトされているのでコメント外す
[include]
files = supervisord.d/*.conf ; 起動するプロセスのconfファイルの配置場所
;files = relative/directory/*.ini

ログファイルは作っておき、パーミッションも設定しておく

$ sudo touch /var/log/supervisord.log
$ sudo chown ec2-user /var/log/supervisord.log
$ sudo chgrp ec2-user /var/log/supervisord.log
$ sudo chmod 774 /var/log/supervisord.log

あと、ログローテションも設定しておく

$ sudo sh -c "echo '/var/log/supervisord.log {
       missingok
       weekly
       notifempty
       nocompress
}' > /etc/logrotate.d/supervisor"

次にデーモン化するプロセスのコマンドを記載したファイルを作っていく
まずはそれらのファイルを配置するディレクトリを作成

$ sudo mkdir /etc/supervisord.d

/etc/supervisord.d配下にdjango_app.confを作成
ここに、Gunicornのプロセスをデーモン化するための設定を以下のように書く

django_app.conf
[program:django_app]
directory=/home/ec2-user/test_project
command=gunicorn test_project.wsgi --bind=0.0.0.0:8000
numprocs=1
autostart=true
autorestart=true
user=ec2-user
redirect_stderr=true

directoryに実行するディレクトリを指定、commandのところにプロセスを起動するためのコマンドを指定する

ここまでできたら下記のコマンドでsupervisorを立ち上げる

$ supervisord

次に、confファイルを読み込ませる
こちらは仮にconfを修正などする場合は必ず実行する

$ supervisorctl reread

なお、下記のコマンドでデーモンを再起動し、そのタイミングでもconfが読み込まれたりする

$ supervisorctl reload

下記のコマンドでGunicornのプロセスをデーモン化する

$ supervisorctl start django_app

仮にdjango_app: ERROR (already started)というメッセージが出た場合は、以下のコマンドでプロセスの再起動をしたり、停止をしてからstartしたりする

$ supervisorctl stop django_app # 停止
$ supervisorctl restart django_app # 再起動

さて、この状態でサーバからログアウトしてみる
そして、http://IPアドレスにアクセスすると、Djangoの画面が表示される
GunicornのプロセスがSupervisorによりデーモン化されていることになる

よかったですね

続きを読む