Amazon ECSでHashiCorp Vaultを動かそうとしてハマった件

問題
Macのローカルで動作していた HashiCorp Vault のDockerイメージをAmazon ECSに持っていったら、タスクが起動停止を繰り返してしまう症状が発生した。

環境
Docker image / 0.8.3, https://hub.docker.com/_/vault/
ECSインスタンス / amzn-ami-2017.03.g-amazon-ecs-optimized (ami-21815747)

原因と対策
ECSインスタンスにログインして、ログを確認したところ、

原因
$ docker logs <CONTAINER ID>
Error initializing core: Failed to lock memory: cannot allocate memory

This usually means that the mlock syscall is not available.
Vault uses mlock to prevent memory from being swapped to
disk. This requires root privileges as well as a machine
that supports mlock. Please enable mlock on your system or
disable Vault from using it. To disable Vault from using it,
set the `disable_mlock` configuration option in your configuration
file.

とのことだった。

一瞬、え?メモリ不足?と思ったのだが、
このECSインスタンスでは mlock が動作しないらしく、
Vaultのconfigに
disable_mlock = 1
を追記し、imageをECRにpushし直したら元気に動くようになった。

めでたしめでたし。

続きを読む

AWS関連用語まとめ

個人的に今勉強中のAWS関連の用語をなるべく簡単にまとめてみました。(語弊がある部分もあるかもしれませんが個人的に理解できる形で落とし込んでみました)。今後も随時追加予定

EC2

仮想サーバ

S3

Amazon Simple Storage Service。オンラインストレージサービス

EBS

Amazon Elastic Block Store。オンライン外付けストレージ

ELB

Elastic Load Barancing。ロードバランサー

EIP

Elastic IP。固定のグローバルIP

RDS

Relational Database Service。クラウド型RDBMS

AMI

Amazon Machine Image。ソフトウェア構成(オペレーティングシステム、アプリケーションサーバー、アプリケーションなど)を記録したテンプレート

IAM

AWS Identity and Access Management。AWSへのアクセスを安全に制御するための仕組み

VPC

Virtual Private Cloud。仮想プライベートクラウド。

CloudFormation

環境設定に関してソースコード化したものを読み込んでAWS上に環境構築してくれるサービス(インフラをコード化してくれるなんてすごいね)

CodePipeline

システムのリリースにおけるプロセスを監視し、自動化・視覚化してくれるサービス。GitHubでMasterブランチへのマージを検知し→ビルド→デプロイ作業を自動で行ってくれる、みたいな事ができる

CodeBuild

CodePipelineで連携している機能の一部。自動でビルドしてくれる

CodeDeploy

CodePipelineで連携している機能の一部。自動でデプロイしてくれる

続きを読む

Elastic BeanStalkの環境別のタグ付を忘れたときにどうすんの?って話

1年ぐらい前からBeanStalk使ってます。
なんつうのか、この辺のAWSのマネージドサービスっていうの?ってほんとすごいですよね。
インフラエンジニアなんか必要なくなりますよね。
AWSの機能をガリガリ使って一昔前の3-tier systemなんて、ネットワークの知識もインフラ系のIeasの知識もなくアプリ屋さんがポチポチやってればいつでも復元できるシステム!が出来上がっちゃうんですもんね。
しかもはやりのECSつかったDockerコンテナの仕組みもつかって・・・
「あ〜〜Dockerとか最近ちゃってもう最近開発とか楽でさ〜〜、インフラ屋?いるの?仕事おせえよあいつら」とかほざけるわけです。

俺なんか無職まっしぐらです。

Beanstalkってなんぞや?

さて、まぁ今更ですがBeanStalkってなんぞやって人に簡単に説明しておきますと、
要は初見殺しとも言えるAWSの「CloudFomartion」を”比較的”わかりやすいUIで設定できるというマネージメントシステムです。
基本はネットワーク層+3tier+インスタンススケーリング何かをある程度コントロールしてくれます
更にアプリケーションのデプロイはソースをまとめておくとECR上にコンテナイメージとして作成してくれたり、そこまで必要ない人でもPHP用のAMIを使ってちょっとPHPで動作させたいコンテンツを作ってデプロイしてみたいな事ができます。
この辺、コンソールでポチポチやってると、たしかに時間的にそれなりのリソースを取られますしで開発したアプリケーションのバージョン管理もソレナリにしてくれるので何度も言いますがとても便利なサービスだと思っています。

BeanStalkのアレなところ

こんなに便利そうなBeanStalkなんですが、サーバサイド(アプリケーション開発者)にはなり針を振り気味なサービスなので、少しでも込み入ったことを始めるととたんに出来ないことが出てきます。
そこで、「.ebextentions」というファイルを作ってアプリ層のレポジトリに拡張設定をおいて設定を入れたりする訳です。
まぁ、デフォルトで設定されるCloudFormationの設定項目をアプリ層に置くようにするわけで、インフラ屋のいない会社なんかだと違和感ないというかとても理にかなっているようにみえるんですが、タスクをサーバサイド・インフラサイドと別けているチームなんかだと

インフラ屋がアプリ屋に土下座をしてネットワーク設定なんかを開発アプリレポジトリに入れてもらう

なんていう状態が発生してしまい、なんとなく自分の存在意義を感じられなくなってきたりもします。

そこで、インフラ屋さんは「EBとかつかってらんねぇよ、せめてCloudFormationでやろうぜ・・・(JSON書きたくないけど)」とか言い始めるわけです。

あ、個人的にはterraformに逃げましたw

本題の環境ごとのタグの調べ方について

なんか、閑話休題のボリュームがいつもまとまらず多めになってしまう訳ですが
本当に書きたかったEBで作った環境に対してのタグの後付とかに関してです。

EBで環境を作るとEBにおけるタグを設定しておけば、そのアプリケーションで起動したEC2インスタンスなどには一応Nameタグがついてくれてどの環境かわかりやすくなるのですが、SecurityGroup・ELB/ALBなどには最初にタグを付け忘れたりすると、どの環境で使っているSG・LBなのかを探すのが非常に困難になります。

具体的には例えばSecurityGroupなんかだと下記のようなタグが付くことになります
– awseb-a-3xxxxx2xxxx-stack-AWSEBSecurityGroup-HOGEFUGE1HOGE

まぁ訳わんないですよね。SGに関してはまだNameのタグを設定しておけば自分で任意に環境名をつけられますが
ELBとかだとName=「ユニークな文字列:DNS名」になっているのでAWSのコンソールやawscliコマンドの返り値だけでは一見どの環境用セット用の機材なのかが全くわからない状態になってしまっています。

また、タグ自体も起動段階で設定していないと、環境をすべてEB的に再構築しない限り(つまり環境内のすべてを捨ててもう一度構築し直す処理)を入れないと追加したNameタグなどは設定されない状況に陥ります。

これをあとでチクチクと手作業で入れることになるんですが、
– awseb-a-3xxxxx2xxxx-stack-AWSEBSecurityGroup-HOGEFUGE1HOGE

この文字列はEBの中身を見ているだけだと判別がつかない物なのです。
なぜか
この文字列自体がCloudformationで作られている物だからですwww。
なのでこのELBがどのEBアプリケーションで使われているのか?というのを調べるためには

  • まず、上記の文字列のうち、「awseb-a-3xxxxx2xxxx-stack」までの部分を抜き出し
  • CloudFormationのスタック一覧のFilterをその文字列に入れ
  • 説明欄にちゃんと記載されている「AWS Elastic Beanstalk environment (Name: ‘hogefuge-app’)」を確認するという作業が必要になります。

まぁ調べる方法がある分マシですがね・・・この辺もうデフォルトでNameダグとしてすべての環境に入れてしまってもいいと思うんですけどね

以上、ちょっとしたボヤキでした。
ちなみに、サーバサイドの方の「構築の手間が楽になるからEB使うことを強く推したい」という要望であるプロジェクトでEB使いましたがもう本サービス運用では二度と使いたくありません・・・・

続きを読む

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 EC2のCentOSをPVからHVMへ移行する

(2年前の下書きを発見したので、時期を外していると思いつつ投稿します)
この記事では、昔から使われていたParaVirtualのEC2インスタンスをHVM対応とし、旧タイプのインスタンスから脱出するための手法を記します。
特に t1.micro で CPU steal に悩んでいる方は早めに t2.micro への移行をおすすめします。CPUクレジットに注意する必要がありますが、早い(CPU/network/storage)安い/うまい(メモリ1GB)と使わない理由がありません。
何度か作業をし、出来るだけ手順化をしてみたのでみなさんと共有します。
可能な限りコマンドライン一撃で終了できるようにしています。

先人の知恵

http://qiita.com/cs_sonar/items/21dbb3462708e146a426
実際の作業手順は上記のエントリーそのままですが、出来るだけsedなどのコマンドを利用しコピペで片付くような手順になっています。

作業用インスタンスを準備する

t2.micro/Amazon Linux(CentOSなどでも問題ないでしょう)でEC2を起動します。
このインスタンスIDが i-IIIIIIII として進めます。

EBSを準備する

作業用のインスタンスにアタッチするためのEBSが必要になります。
必要なEBSは二種類です。

出力先となるEBSを準備する

以下の例では作業の安定性を考慮してio1/PIOPS1000/100GBのEBSを準備します。
移行元のEBSのサイズより大きなものにしましょう。(でないと収まらない)

aws ec2 create-volume --size 100 --availability-zone ap-northeast-1a --volume-type io1 --iops 1000

ここで作成されたEBSボリュームIDを vol-DDDDDDDD として次に進みます。

出力先EBSをアタッチする

aws ec2 attach-volume --instance-id i-IIIIIIII --device /dev/sdo --volume-id vol-DDDDDDDD

元となるEBSを準備する

元となるEBSですが、以下の順序で作成します。
以下の例では作業の安定性を考慮してio1/PIOPS1000/100GBのEBSを準備します。
– 移行元のEBSからスナップショットを作成します。
– 作成したスナップショットから作業用EBSを作成します。

aws ec2 create-snapshot --volume-id vol-OOOOOOOO

ここで作成されたスナップショットのIDを snap-OOOOOOOO として次に進みます。

aws ec2 create-volume --size 100 --availability-zone ap-northeast-1a --volume-type io1 --iops 1000 --snapshot-id snap-OOOOOOOO

作成されたEBSボリュームIDを vol-SSSSSSSS として次に進みます

元となるEBSをアタッチする

aws ec2 attach-volume --instance-id i-IIIIIIII --device /dev/sdm --volume-id vol-SSSSSSSS

作業用インスタンスでの作業

作業用インスタンスには以下の状態でEBSがマウントされている(はず)です。

デバイス名 利用用途
/dev/xvdm 移行元EBS
/dev/xvdo 移行先EBS

移行先データ用EBSを準備する

yum -y install parted resize2fs
parted /dev/xvdo --script 'mklabel msdos mkpart primary 1M -1s print quit'
partprobe /dev/xvdo
udevadm settle

移行元データの検査とディスクサイズの(見かけ上の)縮小

e2fsck -f /dev/xvdm
resize2fs -M /dev/xvdm

移行元EBSから移行先EBSへのデータ移設と縮小したディスクサイズの復元

dd if=/dev/xvdm of=/dev/xvdo1 bs=4K count=1747941
resize2fs /dev/xvdo1

移行先EBSのマウントとchrootによる作業準備

mount /dev/xvdo1 /mnt
cp -a /dev/xvdo /dev/xvdo1 /mnt/dev/
chroot /mnt

grub導入と設定の調整

yum install -y grub
ln -s /boot/grub/menu.lst /boot/grub/grub.conf
ln -s /boot/grub/grub.conf /etc/grub.conf
rm -f /boot/grub/*stage*
cp /usr/*/grub/*/*stage* /boot/grub/
rm -f /boot/grub/device.map
cat <<EOF | grub --batch
device (hd0) /dev/xvdo
root (hd0,0)
setup (hd0)
EOF

menu.lstの調整

menu.lstでの root kernel を調整します。
– (hd0)ではなく(hd0,0)とする必要があります。
– デバイス名ではなくラベル名でrootを認識させます。
– シリアルコンソールとHVM対応を明示します。

sed -i.bak -e 's:root(.*)(hd0):root1(hd0,0):;s:root=.*:root=LABEL=/ console=ttyS0 xen_pv_hvm=enable:' /boot/grub/menu.lst 

以下のような形になっているか確認して下さい。 root kernel あたりが要確認項目です。

default=0
timeout=0
hiddenmenu
title SUZ-LAB CentOS 6
root (hd0,0)
kernel /boot/vmlinuz-2.6.32-431.1.2.0.1.el6.x86_64 ro root=LABEL=/ console=ttyS0 xen_pv_hvm=enable
initrd /boot/initramfs-2.6.32-431.1.2.0.1.el6.x86_64.img

fstabの調整

fstabでのroot(/)をラベルで認識するように変更します。

sed -i.bak -e 's:.*(s)/s(.*)defaults(.*):LABEL=/1/2defaults,noatime3:g' /etc/fstab 

以下のような形になっているか確認して下さい。 LABEL=/ / あたりが要確認項目です。

LABEL=/ /        ext4    defaults,noatime        1 1
none             /proc     proc    defaults        0 0
none             /sys      sysfs   defaults        0 0
none             /dev/pts  devpts  gid=5,mode=620  0 0
none             /dev/shm  tmpfs   defaults        0 0
/mnt/swap/0.img  swap      swap    defaults        0 0

ディスクラベルの調整

e2label /dev/xvdo1 /
tune2fs -l /dev/xvdo1 |grep name

chrootを退出して後片付け

chroot状態から元のOSへ戻ります。

exit

一時的に必要とされたデバイス関連ファイルを削除し、マウントを解除します。

rm -f /mnt/dev/xvdo /mnt/dev/xvdo1
sync
umount /mnt

AMIの作成

AMI作成のもととなるスナップショットを作成する

aws ec2 create-snapshot --volume-id vol-b7f1e741

作成したスナップショットからAMIを作成する

続きを読む

[入門] AMIのコピーでエラーが出たら [EBS Encryption]

こんにちはこむろです。本日もどこにも需要がなさそうな気がする記事をあげていく所存。プログラミングはどこへ。 EBS暗号化の作業に伴い、様々なオペレーションを実行してます。その中でAMIのコピーでいくつか躓いたのでこちらに […] 続きを読む

Djangoの既存プロジェクトをec2にデプロイ

概要

詰まりまくったのでメモ。Dockerで開発していたのでそのままデプロイしたろ!と思っていたが意味わからなすぎて断念。(おそらく?)一般的な方法でデプロイした。もっと良い方法があれば教えて欲しい限りです。

環境

OS: Amazon Linux AMI release 2017.09
ローカル: Docker
Python: 3.6.2
Django: 1.11.5
Gunicorn: 19.7.1
Nginx: 1.12.1

AWSの設定

インスタンスの作成

AWSの設定はAmazon Web Services 基礎からのネットワーク&サーバー構築を参考にした。

AWSに登録してコンソール > EC2からインスタンスを作成する。全部デフォルト。t2microなら無料。
VPC、サブネット、ルートテーブル、ゲートウェイ、セキュリティグループやらが作成される(はず)。なかったら作ってVPCに紐付ける。sshキーをダウンロードまたは登録しておく。

ポートの開放

EC2 > セキュリティグループからポートが開放できる。セキュリティグループを選択 -> インバウンド -> 編集 -> ルールの追加で80番ポート、8000番ポート(確認用、あとで閉じる)を開く。タイプはカスタムTCP、ソースは0.0.0.0/0で良い。
ここで EC2 > インスタンス から作ったインスタンスの詳細が確認できる。右側のパブリックDNSでドメイン、IPv4パブリックIPでIPが確認できる。

nginxのインストール

AWSにsshでログイン。キーペアをダウンロードした場合は~/.sshに置いて別のキー名を指定する。

# ssh -i ~/.ssh/id_rsa ec2-user@(インスタンスのIP)

以下ではrootで作業する。

$ sudo su -

以下、EC2にNginx + Gunicorn + SupervisorでDjangoアプリケーションをデプロイするを参考にnginxをインストール。

nginx入れる。

$ yum install nginx

nginxを起動する。

$ nginx

nginxの自動起動設定

$ chkconfig --add nginx
$ chkconfig nginx on

自動起動設定できているか確認する。

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

また、http://(パブリックDNS)を確認してnginxが起動しているか確認する。

Djangoプロジェクトの起動

AWSにプロジェクトを送る。

scpでzipで固めたDjangoプロジェクトを送る。また送る前にrequirements.txtは用意しておく。

# pip freeze > requirements.txt
# scp -i ~/.ssh/id_rsa ~/path/to/project.zip ec2-user@yourIP:home/ec2-user/

送ったものがhome/ec2-userに落ちているはず。解凍する

$ unzip project.zip

ほんとはgitで落とせばいいんだろうけどプライベートリポジトリにしてるので新しいuser登録して新しくssh登録してってしないといけないのかな。誰か教えてください。

pythonとかを入れる

色々考えるのがめんどくさかったのでEC2サーバにPython3環境構築を参考にした。

gitとpyenv入れる。-yが全部yesって答えるオプションらしい。初めて知った。

$ yum install git -y
$ git clone https://github.com/yyuu/pyenv.git ~/.pyenv

path通す。

$ echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.bash_profile
$ echo 'export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.bash_profile
$ echo 'eval "$(pyenv init -)"' >> ~/.bash_profile
$ source ~/.bash_profile

コマンド通るか確認。

$ pyenv -V

依存関係を入れる。

$ sudo yum install gcc zlib-devel bzip2 bzip2-devel readline readline-devel sqlite sqlite-devel openssl openssl-devel -y

本体を入れる。

$ pyenv install 3.6.2

pythonを切り替える。これはrootのpythonなので、sudo su -後でないとデフォルトのpythonに戻ってしまうので注意。

$ pyenv global 3.6.2
$ pyenv rehash
$ python --version
Python 3.6.2

Django、その他諸々のプロジェクトに必要なライブラリをインストールする。

$ pip install --upgrade -r project/requirements.txt

requirements.txtにGunicornが入ってなければGunicornを入れる。
Gunicornとはwsgiサーバーのことで、nginxとDjangoを繋ぐものみたいなイメージ。

$ pip install gunicorn

manage.pyの上でDjangoを起動させる。

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

http://(パブリックDNS):8000を確認すると、ALLOWED_HOSTSに追加してね!と出るので追加する。

/your_project/settings.py
# 中略
ALLOWED_HOSTS = ['(パブリックDNS)']
# 以下略

もう一回確認してプロジェクトが見えれば成功。

Nginxの設定の変更

再びEC2にNginx + Gunicorn + SupervisorでDjangoアプリケーションをデプロイするを丸パクリ。本当にありがとうございました
/etc/nginx.confとあるが、Amazon Linuxでは/etc/nginx/nginx.confにあった。
以下引用

/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の再起動

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

Djangoを再びGunicornで立ち上げる

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

http://(パブリックDNS)で確認できたら成功。

daemon化

今はコマンドからGunicornを起動しているだけなので、ログアウトしたら終了してしまう。そこでGunicornをデーモン化して常駐するようにしたい。
ただ色々な所を見ると、Surpervisorというツールでそれが可能なようだが、SurpervisorはPython3系に対応していないので2系の環境をもう一つ作れとのこと。んなアホな。
もうちょっと調べてみると、普通に-Dというオプションをつけるだけでデーモンとして起動できるらしい。

起動

$ gunicorn your_project.wsgi --bind=0.0.0.0:8000 -D

終了するときは

$ ps -ef | grep gunicorn
root     17419     1  0 Oct07 ?        00:00:08 /root/.pyenv/versions/3.6.2/bin/python3.6 /root/.pyenv/versions/3.6.2/bin/gunicorn your_project.wsgi --bind=0.0.0.0:8000 -D
root     17422 17419  0 Oct07 ?        00:00:01 /root/.pyenv/versions/3.6.2/bin/python3.6 /root/.pyenv/versions/3.6.2/bin/gunicorn your_project.wsgi --bind=0.0.0.0:8000 -D
root     21686 21594  0 08:05 pts/0    00:00:00 grep --color=auto gunicorn
$ kill 17419

スクリプトで起動

ただこのままだと毎回めんどくさいので、シェルスクリプトでサーバーを起動、停止するにあるスクリプトを使わせてもらう。

Flaskとかで作ったちょっとしたサーバーの起動/停止用のシェルスクリプト。
gunicornでデーモン状態にしている。
startで起動、stopで終了、restartでstop+start。

your_project.sh
#!/bin/sh
PROGNAME=`basename $0`
BASEDIR=`dirname $0`
PIDFILE=$BASEDIR/$PROGNAME.pid

start() {
  echo "Starting server..."
  cd $BASEDIR
  gunicorn flaskhello:app -p $PIDFILE -D
}

stop() {
  echo "Stopping server..."
  kill -TERM `cat $PIDFILE`
  rm -f $PIDFILE
}

usage() {
  echo "usage: $PROGNAME start|stop|restart"
}

if [ $# -lt 1 ];  then
  usage
  exit 255
fi

case $1 in
  start)
    start
    ;;
  stop)
    stop
    ;;
  restart)
    stop
    start
    ;;
esac

以下のgunicorn flaskhello:app -p $PIDFILE -D
gunicorn your_project.wsgi --bind=0.0.0.0:8000 -Dに書き換える。

$ sh your_project.sh start   #起動
$ sh your_project.sh stop    #終了
$ sh your_project.sh restart #再起動

sshを切ってもhttp://(パブリックDNS)が見えたら成功。ひとまず見えるようになった。

staticファイルが見つからない

ただここまで追ってもcss,jsなどstaticファイルは見つかってないはず。以下で見えるようにする。
setting.pyのSTATIC_URL、STATIC_PATHは設定済みでローカルでは見える状態とする。
詳しい解説 -> Django での static files の扱い方まとめ

staticファイルのコピー

manage.pyの上でstaticファイルを指定したディレクトリにコピー

$ python manage.py collectstatic

nginx.confをいじる

nginx.confにstaticファイルのディレクトリを登録する。

/etc/nginx/nginx.conf
server{
    # 〜中略〜
    location /static {
         alias /home/ec2-user/your_project/static;
         #settings.pyで設定したのと同じ場所を記述
    }
    # 〜以下略〜
}

パーミッション変更

ここでnginxとgunicornを再起動する。

$ sh your_project.sh stop
Stopping server...
$ service nginx restart
Stopping nginx:                                            [  OK  ]
Starting nginx:                                            [  OK  ]
$ sh your_project.sh start
Starting server...

するととpermission deniedが出た。これはec2-userにotherからの権限がないせいだった。
参考によると、このディレクトリに移動する権限が必要らしい。
/home/でec2-userに権限を与える。

$ ls -l
drwx------  5 ec2-user ec2-user 4096 Oct  6 04:19 ec2-user
$ chmod o+x ec2-user
$ ls -l
drwx-----x  5 ec2-user ec2-user 4096 Oct  6 04:19 ec2-user

gunicornを再起動すると無事にstaticファイルにアクセスできて終了。

参考

EC2にNginx + Gunicorn + SupervisorでDjangoアプリケーションをデプロイする
EC2サーバにPython3環境構築
シェルスクリプトでサーバーを起動、停止する
Django での static files の扱い方まとめ
Nginxでつくる、どシンプルな静的コンテンツサーバ

続きを読む

開発用サーバーを作る on AWS(Ruby on Rails 5)

はじめに

まぁそのまんま。
こちらのRubyonRails編。

Ruby 2.4.2
Ruby on Rails 5.1.4
なり。

Amazon Linux AMI+Nginx+Unicorn
やで。

インストールなど

sudo yum update
sudo yum -y install git
sudo yum install nodejs --enablerepo=epel
git clone https://github.com/sstephenson/rbenv.git ~/.rbenv
git clone https://github.com/sstephenson/ruby-build.git ~/.rbenv/plugins/ruby-build
echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bash_profile
echo 'eval "$(rbenv init -)"' >> ~/.bash_profile
source ~/.bash_profile
sudo yum install gcc openssl-devel readline-devel sqlite-devel
rbenv install 2.4.2
rbenv global 2.4.2
gem update --system
gem install --no-ri --no-rdoc rails
gem install bundler
gem install sqlite3
gem install unicorn
rbenv rehash
rails -v
rails new /var/www/html/sample
sudo mkdir /var/run/unicorn
sudo chmod 777 /var/run/unicorn
sudo chown -R nginx:ec2-user /var/www/html
sudo chmod 2777 /var/www -R

まぁ、だいぶ時間がかかりまっせ。

sample/config/unicorn.rbを作成

application = 'sample'

worker_processes 2
timeout 15

pid "/var/run/unicorn/unicorn_#{application}.pid"
listen "/var/run/unicorn/unicorn_#{application}.sock"

preload_app true

before_fork do |server, worker|
  Signal.trap 'TERM' do
  puts 'Unicorn master intercepting TERM and sending myself QUIT instead'
  Process.kill 'QUIT', Process.pid
  end

  defined?(ActiveRecord::Base) and
  ActiveRecord::Base.connection.disconnect!end

after_fork do |server, worker|
  Signal.trap 'TERM' do
  puts 'Unicorn worker intercepting TERM and doing nothing. Wait for master to send QUIT'
  end

  defined?(ActiveRecord::Base) and
  ActiveRecord::Base.establish_connection
end

stderr_path File.expand_path('log/unicorn.log', ENV['RAILS_ROOT'])
stdout_path File.expand_path('log/unicorn.log', ENV['RAILS_ROOT'])

起動

bundle exec unicorn_rails -c config/unicorn.rb -E development -D

OSの再起動対応

~/.bashrcに追記

sudo mkdir -p /var/run/unicorn && sudo chmod 777 /var/run/unicorn

/etc/nginx/conf.d/sample.conf作成

upstream unicorn {
  server unix:/var/run/unicorn/unicorn_sample.sock;
}
server {
    listen 8080;
    server_name localhost;
    root /var/www/html/sample;

    access_log /var/log/nginx/myapp_access.log;
    error_log /var/log/nginx/myapp_error.log;

    try_files $uri/index.html $uri @unicorn;
    location @unicorn {
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
        proxy_pass http://unicorn;
    }
}

PHPを80で動かしてる都合上8080でごわす。

Nginx再起動

sudo service nginx restart

いじょー
Security Groupで8080はあけておきましょうね。

by 株式会社Arrvis

続きを読む

Swagger入門&導入 on AWS EC2 Amazon Linux AMI〜Swagger Editor編

はじめに

表題の通り。
入門→Swaggerなんぞやっていうのはググってください。
ほんとはね、Amazon API GatewayとかAWS Lambdaとか使いたいところなんだけどね。
色々な都合上ね。自分とこでやるならもっとイケてるアーキテクチャにするわ。なーんて。
今回はとりあえずswagger-editorを動かすとこまで。

*補足
連載物です。
swagger-editorはその名の通り、エディターですw
他のは今後でてきます。

事前準備

こちらを参考にWebサーバー立てて置いてね。別にApacheでもNginxでもhttp-serverでもなんでもえーよ、たぶん。
ドキュメントルートは/var/www/htmlでっせ。

本編

node.js / npm / wgetが必要らしいよ。Amazon Linux AMIならたぶん最初っから入ってるっぽいよ(クリーンな環境用意するのがめんどくさかったので未確認)。
必要なら以下を。

$ sudo yum install -y nodejs
$ sudo yum install -y npm
$ sudo yum install -y wget

で、swagger-editor。

$ wget https://github.com/swagger-api/swagger-editor/archive/v3.1.9.zip
$ unzip v3.1.9.zip -d /var/www/html
$ mv /var/www/html/swagger-editor-3.1.9/ /var/www/html/swagger

ブラウザで http://hoge.com/swagger/ を開きましょう。
次からはこいつをベースにいじっていきまっせ。

by 株式会社Arrvis

続きを読む