ECS運用のノウハウ

概要

ECSで本番運用を始めて早半年。ノウハウが溜まってきたので公開していきます。

設計

基本方針

基盤を設計する上で次のキーワードを意識した。

Immutable infrastructure

  • 一度構築したサーバは設定の変更を行わない
  • デプロイの度に新しいインフラを構築し、既存のインフラは都度破棄する

Infrastructure as Code (IaC)

  • インフラの構成をコードで管理
  • オーケストレーションツールの利用

Serverless architecture

  • 非常中型プロセスはイベントごとにコンテナを作成
  • 冗長化の設計が不要

アプリケーションレイヤに関して言えば、Twelve Factor Appも参考になる。コンテナ技術とも親和性が高い。

ECSとBeanstalk Multi-container Dockerの違い

以前に記事を書いたので、詳しくは下記参照。

Beanstalk Multi-container Dockerは、ECSを抽象化してRDSやログ管理の機能を合わせて提供してくれる。ボタンを何度か押すだけでRubyやNode.jsのアプリケーションが起動してしまう。
一見楽に見えるが、ブラックボックスな部分もありトラブルシュートでハマりやすいので、素直にECSを使った方が良いと思う。

ALBを使う

ECSでロードバランサを利用する場合、CLB(Classic Load Balancer)かALB(Application Load Balancer)を選択できるが、特別な理由がない限りALBを利用するべきである。
ALBはURLベースのルーティングやHTTP/2のサポート、パフォーマンスの向上など様々なメリットが挙げられるが、ECSを使う上での最大のメリットは動的ポートマッピングがサポートされたことである。
動的ポートマッピングを使うことで、1ホストに対し複数のタスク(例えば複数のNginx)を稼働させることが可能となり、ECSクラスタのリソースを有効活用することが可能となる。

※1: ALBの監視方式はHTTP/HTTPSのため、TCPポートが必要となるミドルウェアは現状ALBを利用できない。

アプリケーションの設定は環境変数で管理

Twelve Factor Appでも述べられてるが、アプリケーションの設定は環境変数で管理している。
ECSのタスク定義パラメータとして環境変数を定義し、パスワードやシークレットキーなど、秘匿化が必要な値に関してはKMSで暗号化。CIによってECSにデプロイが走るタイミングで復号化を行っている。

ログドライバ

ECSにおいてコンテナはデプロイの度に破棄・生成されるため、アプリケーションを始めとする各種ログはコンテナの内部に置くことはできない。ログはイベントストリームとして扱い、コンテナとは別のストレージで保管する必要がある。

今回はログの永続化・可視化を考慮した上で、AWSが提供するElasticsearch Service(Kibana)を採用することにした。
ECSは標準でCloudWatch Logsをサポートしているため、当初は素直にawslogsドライバを利用していた。CloudWatchに転送してしまえば、Elasticsearch Serviceへのストリーミングも容易だったからである。

Network (3).png

しかし、Railsで開発したアプリケーションは例外をスタックトレースで出力し、改行単位でストリームに流されるためログの閲覧やエラー検知が非常に不便なものだった。
Multiline codec plugin等のプラグインを使えば複数行で構成されるメッセージを1行に集約できるが、AWS(Elasticsearch Service)ではプラグインのインストールがサポートされていない。
EC2にElasticsearchを構築することも一瞬考えたが、Elasticsearchへの依存度が高く、将来的にログドライバを変更する際の弊害になると考えて止めた。
その後考案したのがFluentd経由でログをElasticsearch Serviceに流す方法。この手法であればFluentdでメッセージの集約や通知もできるし、将来的にログドライバを変更することも比較的容易となる。

Network (4).png

ジョブスケジューリング

アプリケーションをコンテナで運用する際、スケジュールで定期実行したい処理はどのように実現するべきか。
いくつか方法はあるが、1つの手段としてLambdaのスケジュールイベントからタスクを叩く方法がある(Run task)。この方法でも問題はないが、最近(2017年6月)になってECSにScheduled Taskという機能が追加されており、Lambdaに置き換えて利用可能となった。Cron形式もサポートしているので非常に使いやすい。

運用

ECSで設定可能なパラメータ

ECSコンテナインスタンスにはコンテナエージェントが常駐しており、パラメータを変更することでECSの動作を調整できる。設定ファイルの場所は /etc/ecs/ecs.config
変更する可能性が高いパラメータは下表の通り。他にも様々なパラメータが存在する。

パラメータ名 説明 デフォルト値
ECS_LOGLEVEL ECSが出力するログのレベル info
ECS_AVAILABLE_LOGGING_DRIVERS 有効なログドライバの一覧 [“json-file”,”awslogs”]
ECS_ENGINE_TASK_CLEANUP_WAIT_DURATION タスクが停止してからコンテナが削除されるまでの待機時間 3h
ECS_IMAGE_CLEANUP_INTERVAL イメージ自動クリーンアップの間隔 30m
ECS_IMAGE_MINIMUM_CLEANUP_AGE イメージ取得から自動クリーンアップが始まるまでの間隔 1h

パラメータ変更後はエージェントの再起動が必要。

$ sudo stop ecs
$ sudo start ecs

クラスタのスケールアウトを考慮し、ecs.configはUserDataに定義しておくと良い。
以下はfluentdを有効にしたUserDataの記述例。

#!/bin/bash
echo ECS_CLUSTER=sandbox >> /etc/ecs/ecs.config
echo ECS_AVAILABLE_LOGGING_DRIVERS=["fluentd"] >> /etc/ecs/ecs.config

CPUリソースの制限

現状ECSにおいてCPUリソースの制限を設定することはできない(docker runの--cpu-quotaオプションがサポートされていない)。
タスク定義パラメータcpuは、docker runの--cpu-sharesにマッピングされるもので、CPUの優先度を決定するオプションである。従って、あるコンテナがCPUを食いつぶしてしまうと、他のコンテナにも影響が出てしまう。
尚、Docker 1.13からは直感的にCPUリソースを制限ができる--cpusオプションが追加されている。是非ECSにも取り入れて欲しい。

ユーティリティ

実際に利用しているツールを紹介。

graph.png

ルートボリューム・Dockerボリュームのディスク拡張

ECSコンテナインスタンスは自動で2つのボリュームを作成する。1つはOS領域(/dev/xvda 8GB)、もう1つがDocker領域(/dev/xvdcz 22GB)である。
クラスタ作成時にDocker領域のサイズを変更することはできるが、OS領域は項目が見当たらず変更が出来ないように見える。

Screen_Shot_2017-08-31_at_11_00_03.png

どこから設定するかというと、一度空のクラスタを作成し、EC2マネージメントコンソールからインスタンスを作成する必要がある。

また、既存ECSコンテナインスタンスのOS領域を拡張したい場合は、EC2マネージメントコンソールのEBS項目から変更可能。スケールアウトを考慮し、Auto scallingのLaunch Configurationも忘れずに更新しておく必要がある。

補足となるが、Docker領域はOS上にマウントされていないため、ECSコンテナインスタンス上からdf等のコマンドで領域を確認することはできない。

デプロイ

ECSのデプロイツールは色々ある(ecs_deployerは自分が公開している)。

社内で運用する際はECSでCIを回せるよう、ecs_deployerをコアライブラリとしたCIサーバを構築した。

デプロイ方式

  • コマンド実行形式のデプロイ
  • GitHubのPushを検知した自動デプロイ
  • Slackを利用したインタラクティブデプロイ

Screen_Shot_2017-08-31_at_11_31_15.png

デプロイフロー

ECSへのデプロイフローは次の通り。

  1. リポジトリ・タスクの取得
  2. イメージのビルド
    • タグにGitHubのコミットID、デプロイ日時を追加
  3. ECRへのプッシュ
  4. タスクの更新
  5. 不要なイメージの削除
    • ECRは1リポジトリ辺り最大1,000のイメージを保管できる
  6. サービスの更新
  7. タスクの入れ替えを監視
    • コンテナの異常終了も検知
  8. Slackにデプロイ完了通知を送信

現在のところローリングデプロイを採用しているが、デプロイの実行から完了までにおよそ5〜10分程度の時間を要している。デプロイのパフォーマンスに関してはまだあまり調査していない。

ログの分類

ECSのログを分類してみた。

ログの種別 ログの場所 備考
サービス AWS ECSコンソール サービス一覧ページのEventタブ APIで取得可能
タスク AWS ECSコンソール クラスタページのTasksタブから”Desired task status”が”Stopped”のタスクを選択。タスク名のリンクから停止した理由を確認できる APIで取得可能
Docker daemon ECSコンテナインスタンス /var/log/docker ※1
ecs-init upstart ジョブ ECSコンテナインスタンス /var/log/ecs/ecs-init.log ※1
ECSコンテナエージェント ECSコンテナインスタンス /var/log/ecs/ecs-agent.log ※1
IAMロール ECSコンテナインスタンス /var/log/ecs/audit.log タスクに認証情報のIAM使用時のみ
アプリケーション コンテナ /var/lib/docker/containers ログドライバで変更可能

※1: ECSコンテナインスタンス上の各種ログは、CloudWatch Logs Agentを使うことでCloudWatch Logsに転送することが可能(現状の運用ではログをFluentdサーバに集約させているので、ECSコンテナインスタンスにはFluentdクライアントを構築している)。

サーバレス化

ECSから少し話が逸れるが、インフラの運用・保守コストを下げるため、Lambda(Node.js)による監視の自動化を進めている。各種バックアップからシステムの異常検知・通知までをすべてコード化することで、サービスのスケールアウトに耐えうる構成が容易に構築できるようになる。
ECS+Lambdaを使ったコンテナ運用に切り替えてから、EC2の構築が必要となるのは踏み台くらいだった。

トラブルシュート

ログドライバにfluentdを使うとログの欠損が起きる

ログドライバの項に書いた通り、アプリケーションログはFluentd経由でElasticsearchに流していたが、一部のログが転送されないことに気付いた。
構成的にはアプリケーションクラスタからログクラスタ(CLB)を経由してログを流していたが、どうもCLBのアイドルタイムアウト経過後の最初のログ数件でロストが生じている。試しにCLBを外してみるとロストは起きない。

Network (1).png

ログクラスタ(ECSコンテナインスタンスの/var/log/docker)には次のようなログが残っていた。

time="2017-08-24T11:23:55.152541218Z" level=error msg="Failed to log msg "..." for logger fluentd: write tcp *.*.*.*:36756->*.*.*.*:24224: write: broken pipe"
3) time="2017-08-24T11:23:57.172518425Z" level=error msg="Failed to log msg "..." for logger fluentd: fluent#send: can't send logs, client is reconnecting"

同様の問題をIssueで見つけたが、どうも現状のECSログドライバはKeepAliveの仕組みが無いため、アイドルタイムアウトの期間中にログの送信が無いとELBが切断してしまうらしい(AWSサポートにも問い合わせた)。

という訳でログクラスタにはCLBを使わず、Route53のWeighted Routingでリクエストを分散することにした。

Network (2).png

尚、この方式ではログクラスタのスケールイン・アウトに合わせてRoute 53のレコードを更新する必要がある。
ここではオートスケールの更新をSNS経由でLambdaに検知させ、適宜レコードを更新する仕組みを取った。

コンテナの起動が失敗し続け、ディスクフルが発生する

ECSはタスクの起動が失敗すると数十秒間隔でリトライを実施する。この時コンテナがDockerボリュームを使用していると、ECSコンテナエージェントによるクリーンアップが間に合わず、ディスクフルが発生することがあった(ECSコンテナインスタンスの/var/lib/docker/volumesにボリュームが残り続けてしまう)。
この問題を回避するには、ECSコンテナインスタンスのOS領域(※1)を拡張するか、コンテナクリーンアップの間隔を調整する必要がある。
コンテナを削除する間隔はECS_ENGINE_TASK_CLEANUP_WAIT_DURATIONパラメータを使うと良い。

※1: DockerボリュームはDocker領域ではなく、OS領域に保存される。OS領域の容量はデフォルトで8GBなので注意が必要。

また、どういう訳か稀に古いボリュームが削除されず残り続けてしまうことがあった。そんな時は次のコマンドでボリュームを削除しておく。

# コンテナから参照されていないボリュームの確認
docker volume ls -f dangling=true

# 未参照ボリュームの削除
docker volume rm $(docker volume ls -q -f dangling=true)

ECSがELBに紐付くタイミング

DockerfileのCMDでスクリプトを実行するケースは多々あると思うが、コンテナはCMDが実行された直後にELBに紐付いてしまうので注意が必要となる。

bundle exec rake assets:precompile

このようなコマンドをスクリプトで実行する場合、アセットがコンパイル中であろうがお構いなしにELBに紐付いてしまう。
時間のかかる処理は素直にDockerfile内で実行した方が良い。

続きを読む

OpsWorks with Rails 環境でDB Migration問題をなんとかする

はじめに

AWS OpsWorksではChef11を選択すると、Railsスタックをデフォルトで提供しており、エンジニアが自前でChefなど用意しなくてもHeroku感覚でAWSをPaaSとして利用することが出来ます。

  • Herokuほどフルマネージドは要件上出来ないが、インフラはある程度管理したい
  • Chef実行準備が面倒くさい
  • コードのDeploy機能とデプロイ記録とりたい
  • CloudWatch Logs統合 (ログPath設定を画面から出来る)
  • AWSビジネスサポートに入っていると、困っている時に技術的なことを直接チケットを投げて聞ける

こんなメリットたちがあります。正直最後のメリットが一番のような気もしますが・・・

DB Migration問題?

このサービスには致命的な問題があります。なんと複数インスタンスへのデプロイ時に、RailsのDB Migrationと、Unicornの再起動の同期が全く取れていません。 そのため、複数インスタンスを選択した状態で、DB Migrationを実行すると、Migration以外のノードはソース反映後すぐにUnicorn再起動がかかり、高確率で不完全な状態でデプロイされてしまいます。

OpsWorks上でのMigration実行の仕組み

OpsWorks経由で「Migrate YES」を選択してデプロイを行うと rake の db:migrate が実行されます。
https://github.com/aws/opsworks-cookbooks/blob/2209f35fc0e3fd7a75af2e3d0715d425c6a55783/deploy/attributes/deploy.rb#L79

複数ノードがある状態で、「Migrate YES」を選択してデプロイを行う場合、グループ内で任意のノード1個が選択され(基本的にはグループで一番最初のもの)、そのノードに対して内部的にchefの変数に default[:deploy][application][:migrate] = true が設定入り、その後、全ノードに同時にcookbookが実行されます。

デプロイ中は、基本的に全てのインスタンスはそれぞれ勝手にChefが実行されるだけです。そのため、これが原因でマイグレーション同期されない問題がおきています。小さなDBマイグレーションであれば問題なかったりしますが、ちょっとでも時間がかかるようになるとアウトです。規模によりますが、Railsのデプロイを1回実行するのに少なくとも3〜4分くらいかかりますので、ダウンタイム発生となります

不完全な状態でのUnicorn再起動を回避する方法 by AWS

AWSサポート等にもヒアリングした所、以下2点の方針が一般的との回答。

  1. Migration用のレイヤーを作っていただき、先にそちらでMigration込みで一旦ソースを反映して頂く
  2. Chefのデプロイフックがあるので、それを利用して何かしら処理を入れてもらう

うーむ、自前でやらねば・・・・ということで素直に上記を対応します。
(1)に関してはただの運用フロー寄りの問題なので、一旦今回は詳細を割愛します。

デプロイフック実装

OpsWorksはDocument Root配下に deploy ディレクトリ配下に before_symlink.rb (シンボリックリンク張替え直前) で以下のチェック入れます。

Chef::Log.info("Running deploy/before_symlink.rb")
current_release = release_path
env = node[:deploy][:app_rails][:rails_env]

execute "rake aws:verify_migration" do
  cwd current_release
  command "bundle exec rake aws:verify_migration"
  environment new_resource.environment.merge({ "RAILS_ENV" => env })
end

Rakeタスクを適当に作ります。

namespace :aws do
  task verify_migration: :environment do
    raise StandardError if 
  ActiveRecord::Migrator.needs_migration?
  end
end

これでとりあえず、不完全な状態でUnicornが再起動される問題だけ回避しました。before_symlinkの段階で、verify_migrationを実行し、マイグレーションが残っている状態の時は対象インスタンスの反映を途中中断させるようにします。「カラムの削除の時はどうするのか」みたいな懸念はありますが、一旦これだけでも入れておけば大きい所はカバーできそうです。

最後に

そもそもChefは諦めて、コンテナ運用(GKE + Spinnaker) に早く移行したほうがいいかもしれない

続きを読む

Rails5アプリケーションのAWSによるネットワーク構築 Nginx+Puma+Capistranoな環境とAWS構築(VPC EC2 RDS CloudFlont Route53 etc)

はじめに

数ヶ月前に書いたRails5のAWS構築をもう少し項目を増やしてから公開しようと思っていたのですが、なかなか出来ないのでもう公開します。(ELBとかCloudFlontとかもっとちゃんと書けそう、、)
項目の追加や修正は適宜入れると思います。

Railsは5.0を使っています。(記事を書いたときの最新)

4系は以前書きました↓

構築する環境

  • VPC
  • EC2
    • Nginx + Puma
    • Capistrano
  • (S3)
  • ELB
  • RDS
  • CloudFlont
  • Route53
  • (CloudWatch)

VPC、EC2のインスタンスの作成

AWSのデザインが多少変更はありますが、以下を参考に作成出来ます。

AWS VPCによるネットワーク構築とEC2によるサーバー構築

これに追加でElastic IPの設定もしておきました。

EC2内の環境構築

作成したEC2にログインして環境を構築します。
ec2-userでまずログインしましょう。

ユーザーの作成

デフォルトではec2-userなので新たなユーザーを追加し、そのユーザーでsshログイン出来るように設定します。

$ sudo adduser shizuma #ユーザーの追加 「shizuma」の部分は好きなユーザー名にします。以後「shizuma」の部分は各自のユーザー名になります。
$ sudo passwd shizuma
#ここで、新規ユーザーのパスワードを設定します。
$ sudo visudo
-----------------------------
#vimが起動するので新規ユーザーにroot権限を与える。
root    ALL=(ALL)       ALL
shizuma ALL=(ALL)       ALL #この行を追加
-----------------------------
$ sudo su - shizuma #ユーザー切り替え
#先ほど設定したパスワード

ここでローカルに一旦戻り、鍵を作成します。

$ cd .ssh
$ ssh-keygen -t rsa
-----------------------------
Enter file in which to save the key ():first_aws_rsa #ここでファイルの名前を記述して、エンター
Enter passphrase (empty for no passphrase): #何もせずそのままエンター
Enter same passphrase again: #何もせずそのままエンター
-----------------------------
$ vi config
-----------------------------
# 以下を追記
Host first_aws
  Hostname 54.64.22.197 #自分の設定に合わせて
  Port 22
  User shizuma #先ほどのユーザー名
  IdentityFile ~/.ssh/first_aws_rsa #秘密鍵の設定
-----------------------------

次に、サーバーに戻り作成した 公開鍵 をサーバーに設定します。

$ mkdir .ssh
$ chmod 700 .ssh
$ cd .ssh
$ vi authorized_keys
-----------------------------
#localの「first_aws_rsa.pub」の中身のコピペ。(localで $ cat first_aws_rsa.pubとかすると良い)
ssh-rsa sdfjerijgviodsjcIKJKJSDFJWIRJGIUVSDJFKCNZKXVNJSKDNVMJKNSFUIEJSDFNCJSKDNVJKDSNVJNVJKDSNVJKNXCMXCNMXNVMDSXCKLMKDLSMVKSDLMVKDSLMVKLCA shizuma@shizuma-no-MacBook-Air.local
-----------------------------
$ chmod 600 authorized_keys
$ exit
$ exit

これで設定が完了したので、以降作成したユーザーでアクセスするようにします。

基本ライブラリとrubyの環境構築

$ sudo yum install 
git make gcc-c++ patch 
openssl-devel 
libyaml-devel libffi-devel libicu-devel 
libxml2 libxslt libxml2-devel libxslt-devel 
zlib-devel readline-devel 
mysql mysql-server mysql-devel 
ImageMagick ImageMagick-devel 
epel-release
$ sudo yum install nodejs npm --enablerepo=epel
$ git clone https://github.com/sstephenson/rbenv.git ~/.rbenv
$ echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bash_profile
$ echo 'eval "$(rbenv init -)"' >> ~/.bash_profile
$ source .bash_profile
$ git clone https://github.com/sstephenson/ruby-build.git ~/.rbenv/plugins/ruby-build
$ rbenv rehash
$ rbenv install -v 2.3.1
$ rbenv global 2.3.1
$ rbenv rehash
$ ruby -v

gitの設定

最低限の設定だけしておきます。

$ vi .gitconfig
.gitignore
[user]
  name = your_name #自分の名前
  email = hoge@hoge.com #自分のメアド

[alias] #これはお好きに
  a = add
  b = branch
  ch = checkout
  st = status

[color] #色付け
  ui = true

[url "github:"] #pull、pushのための設定
    InsteadOf = https://github.com/
    InsteadOf = git@github.com:

アプリケーションフォルダの設置

/var/www/rails にアプリケーションフォルダを設置します。

$ cd /
$ sudo mkdir -p /var/www/rails
$ sudo chown -R shizuma var/www

GitHubの接続とアプリケーションのclone

$ cd ~/.ssh
$ ssh-keygen -t rsa
-----------------------------
Enter file in which to save the key ():aws_git_rsa #ここでファイルの名前を記述して、エンター
Enter passphrase (empty for no passphrase): #何もせずそのままエンター
Enter same passphrase again: #何もせずそのままエンター
-----------------------------
$ chmod 744 config
$ vi config
-----------------------------
# 以下を追記
Host github github.com
  Hostname github.com
  User git
  Port 22
  IdentityFile ~/.ssh/aws_git_rsa #秘密鍵の設定
-----------------------------
$ cat aws_git_rsa.pub
-----------------------------
ssh-rsa sdfjerijgviodsjcIKJKJSDFJWIRJGIUVSDJFKCNZKXVNJSKDNVMJKNSFUIEJSDFNCJSKDNVJKDSNVJNVJKDSNVJKNXCMXCNMXNVMDSXCKLMKDLSMVKSDLMVKDSLMVKLCA shizuma@ip-10-0-1-10
-----------------------------

ここで、これをコピペしてgithubに公開鍵を登録する。
githubへの鍵の登録がよくわからない方は以下の記事を参考に。
gitHubでssh接続する手順~公開鍵・秘密鍵の生成から~

そして、git clone する。

$ cd /var/www/rails
$ git clone https://github.com/kuboshizuma/cheerfull # 自分のアプリケーション

RDSの設定

EC2の環境構築に一区切りついたのでRDSの設定を行います。

DBサブネットの登録

RDSで使うサブネットを登録します。
この設定には異なるアベイラビリティゾーンにあるサブネットが最低1つずつ計2つ必要になります。
また、Railsアプリケーションをおいたサブネットはゲートウェイに繋がったpublicなサブネットなので、privateなサブネットを異なるアベイラビリティゾーンに一つずつ作成します。

スクリーンショット_2017-03-04_11_56_01.png

パラメータグループの設定

パラメータグループを設定します。
mysqlを使用していると設定なので、ここではmysqlを選択します。バージョンは適宜選択。
「chara…」で検索すると出て来るcharasetをutf-8に変更。

スクリーンショット_2017-03-04_12_00_57.png

設定が完了した後に、パラメータの編集を押してパラメーター変更。

スクリーンショット_2017-03-04_12_04_29.png

セキュリティグループの作成

VPCでセキュリティグループを作成します。

スクリーンショット_2017-03-04_12_08_19.png

インバウンドルールにMySQLを設定し、MySQLのアクセスのみ許可します。
「送信元」は0.0.0.0/0で設定。特定のRailsアプリケーションサーバーがあるサブネットに限定するほうがよさそう。

スクリーンショット 2017-03-04 12.55.42.png

RDSインスタンスの作成

エンジンの選択

スクリーンショット_2017-03-04_12_12_05.png

本番稼働用?

スクリーンショット_2017-03-04_12_12_45.png

DB詳細設定の指定

無料枠はt2.micro

スクリーンショット_2017-03-04_12_17_35.png

詳細設定の設定

各種作成したもので設定。

スクリーンショット_2017-03-04_12_19_44.png

スクリーンショット_2017-03-04_12_19_53.png

接続確認

hostは各自の作成したRDSインスタンスのエンドポイントをみる。

$ mysql -h hogepoge.ap-northeast-1.rds.amazonaws.com -u shizuma -P 3306 -p

接続出来たら完了!

絵文字の扱い

絵文字も登録出来るようにする場合。
以下を参考に utfmb4を採用する。

ActiveRecordをutf8mb4で動かす

MAMPでは /Applications/MAMP/conf/my.cnfmy.cnf を設置した。

Railsアプリケーションの起動のための準備

puma setting

以下を追記する。

cofig/puma.rb
# add setting for production
_proj_path = "#{File.expand_path("../..", __FILE__)}"
_proj_name = File.basename(_proj_path)
_home = ENV.fetch("HOME") { "/home/#{ENV['PUMA_USER']}" }
pidfile "#{_home}/run/#{_proj_name}.pid"
bind "unix://#{_home}/run/#{_proj_name}.sock"
directory _proj_path
# add end

ENV['PUMA_USER'] にサーバーのユーザー名が入るように環境変数を設定。

database setting

以下のように編集。

config/database.yml
production:
  <<: *default
  database: cheerfull
  username: <%= ENV['DATABASE_USER_NAME_PRODUCTION'] %>
  password: <%= ENV['DATABASE_PASSWORD_PRODUCTION'] %>
  host: <%= ENV['DATABASE_HOST_PRODUCTION'] %>

それぞれ該当の環境変数を設定。

rake secret

以下のsecret keyの箇所に値が入るように環境変数を設定。
rake secret とコマンドを打つと出て来る文字列を設定する。

config/secrets.yml
production:
  secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>
$ gem install bundler
$ bundle install
$ rake db:create RAILS_ENV=production
$ rake db:migrate RAILS_ENV=production

PumaとNginxの起動

Pumaの起動

アプリケーションディレクトリにて以下を実行。

$ RAILS_SERVE_STATIC_FILES=true RAILS_ENV=production puma -w 4

「Ctr+c」でプロセス消さなければ生き残る。
プロセス消す必要があれば以下のようにする。

$ ps aux | grep puma # プロセスIDを探す
$ kill -9 (ID)

Nginx の起動

「cheerfull」の部分は自分のアプリケーションディレクトリ名に変更する。

/etc/nginx/conf.d/cheerfull.conf
  # log directory
  error_log  /var/www/rails/cheerfull/log/nginx.error.log;
  access_log /var/www/rails/cheerfull/log/nginx.access.log;
  upstream app_server {
    # for UNIX domain socket setups
    server unix:/home/shizuma/run/cheerfull.sock fail_timeout=0;
  }
  server {
    listen 80;
    server_name 12.134.156.178; # 自分のIP
    # nginx so increasing this is generally safe...
    # path for static files
    root /var/www/rails/cheerfull/public;
    # page cache loading
    try_files $uri/index.html $uri @app_server;
    location / {
      # HTTP headers
      proxy_pass http://app_server;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header Host $http_host;
      proxy_redirect off;
    }
    # Rails error pages
    error_page 500 502 503 504 /500.html;
    location = /500.html {
      root /var/www/rails/cheerfull/public;
    }
    client_max_body_size 4G;
    keepalive_timeout 5;
  }

ユーザーをnginxから自分のユーザー名に変更しておく。

/etc/nginx/nginx.conf
#user nginx;
user shizuma;

nginxを起動します。

$ sudo service nginx restart

これで、IPアドレスでアクセスするとアプリケーションが表示されるようになりました。

Capistranoの設定

諸々動くことが確認出来たのでデプロイが出来るように設定します。
デプロイのためにCapistranoの設定をします。
慣れてきたら、いきなりCapistranoの設定をしていけばいいと思います。

socketの場所もアプリケーションディレクトリに変更するのでnginxの設定もそれに合わせて変更します。

「cheerfull」の部分は自分のアプリケーション名に変更する。

deploy.rb
require 'dotenv'
Dotenv.load

lock "3.7.1"

set :application, "cheerfull"
set :repo_url, "git@github.com:your_gitname/cheerfull.git"
set :branch, 'master'
set :deploy_to, '/var/www/rails/protospacce'
set :linked_files, fetch(:linked_files, []).push('.env')
set :linked_dirs, fetch(:linked_dirs, []).push('log', 'tmp/pids', 'tmp/cache', 'tmp/sockets', 'vendor/bundle', 'public/system')
set :keep_releases, 5
set :rbenv_ruby, '2.3.1'

# puma setting
set :puma_threads,    [4, 16]
set :puma_workers,    0
set :pty,             true
set :use_sudo,        false
set :stage,           :production
set :deploy_via,      :remote_cache
set :deploy_to,       "/var/www/rails/#{fetch(:application)}"
set :puma_bind,       "unix://#{shared_path}/tmp/sockets/#{fetch(:application)}-puma.sock"
set :puma_state,      "#{shared_path}/tmp/pids/puma.state"
set :puma_pid,        "#{shared_path}/tmp/pids/puma.pid"
set :puma_access_log, "#{shared_path}/log/puma.error.log"
set :puma_error_log,  "#{shared_path}/log/puma.access.log"
set :puma_preload_app, true
set :puma_worker_timeout, nil
set :puma_init_active_record, true

namespace :deploy do
  desc 'Create database'
  task :db_create do
    on roles(:db) do |host|
      with rails_env: fetch(:rails_env) do
        within current_path do
          execute :bundle, :exec, :rake, 'db:create'
        end
      end
    end
  end
end

実際にdeployする前に、共有ファイルは用意しておきましょう。この場合、.env

ここでpumaのセッティングをしたので、config/puma.rb はもう不要になります。
また、dotenvを使用する場合は変更を読み込むために config/deploy/templates/puma.rb.erb を用意します。以下を用意。

config/deploy/templates/puma.rb.erb
#!/usr/bin/env puma

directory '<%= current_path %>'
rackup "<%=fetch(:puma_rackup)%>"
environment '<%= fetch(:puma_env) %>'
<% if fetch(:puma_tag) %>
  tag '<%= fetch(:puma_tag)%>'
<% end %>
pidfile "<%=fetch(:puma_pid)%>"
state_path "<%=fetch(:puma_state)%>"
stdout_redirect '<%=fetch(:puma_access_log)%>', '<%=fetch(:puma_error_log)%>', true


threads <%=fetch(:puma_threads).join(',')%>

<%= puma_bind %>
<% if fetch(:puma_control_app) %>
activate_control_app "<%= fetch(:puma_default_control_app) %>"
<% end %>
workers <%= puma_workers %>
<% if fetch(:puma_worker_timeout) %>
worker_timeout <%= fetch(:puma_worker_timeout).to_i %>
<% end %>

<% if puma_preload_app? %>
preload_app!
<% else %>
prune_bundler
<% end %>

on_restart do
  puts 'Refreshing Gemfile'
  ENV["BUNDLE_GEMFILE"] = "<%= fetch(:bundle_gemfile, "#{current_path}/Gemfile") %>"
  ENV.update Dotenv::Environment.new('.env')
end

<% if puma_preload_app? and fetch(:puma_init_active_record) %>
before_fork do
  ActiveRecord::Base.connection_pool.disconnect!
end

on_worker_boot do
  ActiveSupport.on_load(:active_record) do
    ActiveRecord::Base.establish_connection
  end
end
<% end %>
$ bundle exec production cap puma:config 

これでこの設定を本番に反映。

あとはデプロイコマンドを打つ。

$ bundle exec cap production deploy

デプロイdone!

nginxのlogの位置やsocketの位置を変更します。

/etc/nginx/conf.d/cheerfull.conf
  # log directory
  error_log  /var/www/rails/cheerfull/shared/log/nginx.error.log;
  access_log /var/www/rails/cheerfull/shared/nginx.access.log;
  upstream app_server {
    # for UNIX domain socket setups
    server unix:/var/www/rails/cheerfull/shared/tmp/sockets/cheerfull-puma.sock fail_timeout=0;
  }
  server {
    listen 80;
    server_name 12.134.156.178; # 自分のIP
    # nginx so increasing this is generally safe...
    # path for static files
    root /var/www/rails/cheerfull/current/public;
    # page cache loading
    try_files $uri/index.html $uri @app_server;
    location / {
      # HTTP headers
      proxy_pass http://app_server;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header Host $http_host;
      proxy_redirect off;
    }
    # Rails error pages
    error_page 500 502 503 504 /500.html;
    location = /500.html {
      root /var/www/rails/cheerfull/current/public;
    }
    client_max_body_size 4G;
    keepalive_timeout 5;
  }
$ sudo service nginx restart

これで、デプロイ環境が整いました。
以前起動したpumaのプロセスはきっておきましょう。

複数サーバーへのデプロイ

multiconfig を使用します。

Gemfile
gem 'capistrano-multiconfig', '~> 3.1', require: false

Capfileのcapistrano/setupから変更。

Capfile
# require "capistrano/setup"
require 'capistrano/multiconfig'

config/deploy/production.rb から config/deploy/app1/production.rb に変更する。
以下のようにdeploy出来るようになる。

$ bundle exec cap app1:production deploy

違うサーバーにデプロイするときは同じように config/deploy/app2/production.rb を準備すればオーケー。

$ bundle exec cap app2:production deploy

これで違うサーバーにデプロイ出来る。

これまでと同様にec2サーバーをもう一度用意して2箇所にデプロイ出来るようにする。

ロードバランサー ELB

ロードバランサーをhttpsで運用したいときadmin@hoge.comのようなアドレスへのメールを受信可能のしないといけない。

以下でとりあえずzoneファイルのインポートまでする。
Amazon Route53 ネームサーバへの移行手順(お名前.comからの)

その後にこの記事にあるようにお名前.com側の設定をする。
お名前.com + Route53で独自ドメインのメールをGmailに転送する

メールの転送が出来ていることを確認する。
そして、ELBの指示に従って設定。
下記参考。
【初心者向け】ELBにSSL証明書をインストールする

そこまでしたら
Amazon Route53 ネームサーバへの移行手順(お名前.comからの)
の続きでELBとつなげる。

注意点は、ターゲットグループにトラフィックをルーティングするときのプロトコルをHTTPにすること。これでELBへはHTTPSでアクセス出来、それをアプリケーションではHTTPで扱うことが出来る。

また、以下のように nginxのサーバーネームにドメイン名を追加する必要がある。

server_name hogepoge.com 00.000.00.00 sakamichi-app-elb-000000000.ap-northeast-1.elb.amazonaws.com

CloudFront

Amazon CloudFront + ACM 独自ドメインで HTTPS (SSL) 配信設定メモ

CloudWatchとか

必要の応じて加筆。

続きを読む

Rails + CircleCI 1.0 + AWS の設定手順 ビルド開始~デプロイ完了まで

はじめに

RailsでCircleCI環境を整えるまでの手順をまとめました。

CircleCIはバージョン2.0がありますが、
Dockerがないといけない?ようなので、バージョン1.0で準備しました。

circleCIとは

簡単に言うと、
githubのpushを検知して、自動でビルドからテスト、デプロイまで自動化してくれるツール。
(デフォルトだと全部ブランチ対象)

1コンテナは無料なので、時間が掛かってもよいのであれば無料枠で十分。

https://circleci.com/

設定ファイル

必要なファイルは以下3つ

① circle.yml
② config/database.yml.ci
③ script/deploy-staging.sh

① circle.yml

circleCIを動かくための設定ファイル。
Railsのアプリケーションディレクトリ直下にファイルを作ります。(gemfileとかと同じ場所)

② config/database.yml.ci

テストするためのDB設定ファイル。Rspecを実行するために必要。

③ script/deploy-staging.sh

テストが終わったらステージング環境へデプロイするためのスクリプトファイル。

設定ファイルの中身

circle.yml
machine:
  timezone:
    Asia/Tokyo
  ruby:
    version:
      2.3.0
dependencies:
  pre:
    - sudo pip install awscli
  override:
    - bundle install:
database:
  pre:
    - mv config/database.yml.ci config/database.yml
  override:
    - bundle exec rake db:create db:schema:load RAILS_ENV=test
    - bundle exec rake db:migrate RAILS_ENV=test
test:
  override:
    - bundle exec rspec spec/
deployment:
  staging:
    branch: master
    commands:
      - sh script/deploy-staging.sh:
          timeout: 1500

ポイント
AWSにデプロイするのにawscliを使用するために、
「sudo pip install awscli」を記述する。(デフォルトは古いらしい)
DB名は「test」じゃないと動かない。

config/database.yml.ci
test:
  adapter: postgresql
  encoding: unicode
  database: test
  pool: 5
script/deploy-staging.sh
#!/bin/sh

export AWS_DEFAULT_REGION="ap-northeast-1"

MYSECURITYGROUP="*"
MYIP=`curl -s ifconfig.me`

aws ec2 authorize-security-group-ingress --group-id $MYSECURITYGROUP --protocol tcp --port 22 --cidr $MYIP/32

bundle exec cap production deploy

aws ec2 revoke-security-group-ingress --group-id $MYSECURITYGROUP --protocol tcp --port 22 --cidr $MYIP/32

ポイント
MYSECURITYGROUPは、AWSのセキュリティーグループIDを指定する。
LFの改行コードで作成する。CRLFだと動かない。

その他設定

CircleCI側にAWSの秘密鍵を登録する。
AWS上で「cat ~/.ssh/id_rsa」で表示されるもの。

CircleCI側にAWSのアクセスキーとシークレットキーを設定

AWSの秘密鍵をAWSの認証キーとして登録。
AWS上で「cat id_rsa >> ~/.ssh/authorized_key」

Port 22をセキュリティグループで空けておく。

続きを読む

Rails5+Puma+Nginxな環境をCapistrano3でEC2にデプロイする(前編)

Rails5系で新しく開発しているウェブアプリケーションを、AWSのEC2で稼働している本番環境にCapistranoでデプロイすることになったときのお話です。これまで個人でなにかを開発する際にはRails4系でアプリケーションサーバにUnicornを採用していましたが、今回からはPumaを採用することにしたのでその手順です。前回の手順はこちらです。
Rails4 & Unicorn & Nginx & EC2でサーバー構築

前提

  • Rails 5.0.0
  • Ruby 2.4.0
  • rbenv 0.4.0
  • Puma
  • Nginx
  • Capistrano 3.7.0
  • Amazon Linux AMI 2017.03.0 (HVM)

手順

  • 1. 必要なGemを追加
  • 2. Capistranoの設定を追加
  • 3. デプロイ実行ユーザを作成
  • 4. アプリケーション用のディレクトリを作成
  • 5. 接続に必要な鍵を作成
  • 6. AgentFowardを設定
  • 7. 接続を確認
  • 8. おもむろにデプロイしてみる

1. 必要なGemを追加

まずはデプロイに必要なGemを追加する。capistrano-rbenv-vars はPumaで環境変数を読むために使っている。

Gemfile
# Use Puma as the app server
gem 'puma', '~> 3.0'

group :development do
  gem 'capistrano', '3.7.0'
  gem 'capistrano-rails'
  gem 'capistrano-bundler'
  gem 'capistrano-rbenv'
  gem 'capistrano-rbenv-vars'
end
$ bundle exec bundle install

2. Capistranoの設定を追加

インストールのためのコマンドがあるので使う。コマンドを使わずに手動でファイルを作成してもよいが、今回はこちらのコマンドで生成する。

$ bundle exec cap install

以下のファイルがざっと生成される。 deploy.rb に共通の設定を書いておいて、ステージング環境と本番環境の固有の設定は staging.rbproduction.rb にそれぞれ記述していく。

  • Capfile
  • config/deploy.rb
  • config/deploy/staging.rb
  • config/deploy/production.rb
  • lib/capistrano/tasks

以下にデプロイを成功させるための最低限の設定を記載しておく。ほぼ初期設定のためおそらくこのままではアプリケーションはきっと動かないので、自身の環境に合わせてよきに追加、削除する。まずは デプロイが正常に終了する ことにゴールとして進める。

Capfile
require "capistrano/setup"
require "capistrano/deploy"
require "capistrano/scm/git"

install_plugin Capistrano::SCM::Git

Dir.glob("lib/capistrano/tasks/*.rake").each { |r| import r }
deploy.rb
lock "3.7.0"

set :application, "my-app-name"
set :repo_url, "git@github.com:kappy/my-app-name.git"
ask :branch, `git rev-parse --abbrev-ref HEAD`.chomp

namespace :deploy do
  desc "Make sure local git is in sync with remote."
  task :confirm do
    on roles(:app) do
      puts "This stage is '#{fetch(:stage)}'. Deploying branch is '#{fetch(:branch)}'."
      puts 'Are you sure? [y/n]'
      ask :answer, 'n'
      if fetch(:answer) != 'y'
        puts 'deploy stopped'
        exit
      end
    end
  end

  desc 'Initial Deploy'
  task :initial do
    on roles(:app) do
      invoke 'deploy'
    end
  end

  before :starting, :confirm
end
production.rb
server "xx.xxx.xxx.xxx", user: "deploy", roles: %w{app db web}

set :ssh_options, {
  keys: %w(~/.ssh/id_rsa),
  forward_agent: true,
  auth_methods: %w(publickey)
}

3. デプロイ実行ユーザを作成(EC2)

Capistranoでデプロイを行うために、デプロイ用のユーザを作成してデプロイ対象のEC2に対しsshで接続できるように権限を与える。

まずは既存のユーザでログインする。

$ ssh -i "~/.ssh/xxxxx.pem" ec2-user@ec2-xx-xxx-xxx-xxx.ap-northeast-1.compute.amazonaws.com

デプロイ用のユーザを作成し、sudoコマンドが実行できるように権限を与える。 /etc/sudoers ファイルを編集すればよいのだが $ sudo vi /etc/sudoers では読み取り専用になってしまうため $ sudo visudo で行なっている。

$ sudo su -
$ useradd deploy
$ passwd deploy

$ sudo visudo
root   ALL=(ALL) ALL
deploy ALL=(ALL) ALL ← この1行を追加

$ exit

exitしてec2-userに戻り作成したdeployユーザで入れるか確認する。

$ su - deploy

4. アプリケーション用のディレクトリを作成(EC2)

デプロイ対象となるアプリケーション用のディレクトリを準備する。Capistranoのデフォルト設定では /var/www/my_app_name となっているため、特に理由がなければこちらのパスに沿うようにする。my_app_name は自身のアプリ名で置き換えればよい。

$ su - deploy

$ pwd
/home/deploy

$ sudo mkdir www && cd www
$ sudo mkdir my_app_name && cd my_app_name
$ sudo chown deploy:deploy my_app_name

5. 接続に必要な鍵を作成(EC2)

ローカルマシン(以下、ローカル)からEC2に接続するための鍵をつくる。作成した鍵を authorized_keys に名前を変えているのはAWS側のSSHの初期設定に沿うようにするため。こちらの設定は /etc/ssh/sshd_configAuthorizedKeysFile に記述されているが、変更する理由もないのでこちらに合わせる。

$ pwd
/home/deploy

$ sudo mkdir .ssh && cd .ssh
$ ssh-keygen -t rsa
$ mv id_rsa.pub authorized_keys

$ chmod 600 authorized_keys
$ chmod 700 ../.ssh

$ cat id_rsa

後にこの秘密鍵を使用してEC2に接続するため、作成した秘密鍵(id_rsa)はローカルの ~/.ssh/id_rsa などに保存しておく。

6. AgentFowardを設定

今回の設定ではローカルに保存した秘密鍵を使用してEC2に接続し、EC2に保存した秘密鍵を使用してGithubに接続してソースコードを取得する。Githubへの接続はローカルの秘密鍵を使用するため、ローカルでAgentFowardを設定する。

まずは現在の設定状態を確認する。

$ ssh-add -l

先ほど作成した秘密鍵を追加する。-K オプションを付けているのはKeychainに設定を保存しておくため。この設定がないと再起動するたびに設定が消えてしまう。

$ ssh-add -K ~/.ssh/id_rsa

7. 接続を確認

鍵の登録が正しく行われていれば以下のようなコマンドで鍵の指定をせずに接続ができるようになる。パスフレーズを入力し公開鍵認証での接続が成功していることを確認する(パスフレーズを設定せず鍵の作成を行えばいいよと書いている記事があるがそれは間違い)。

$ ssh deploy@xx.xxx.xxx.xxx

8. おもむろにデプロイしてみる

ここまでで、とりあえずデプロイを実行してみる。きっと失敗するががんばってエラーを逐一解消していく。エラーログはちゃんと読みましょう。

$ bundle exec cap production deploy

以下のデプロイタスクが正常に完了すればCapistrano側の設定はひとまずおわり。

  • git:wrapper
  • git:check
  • deploy:check:directories
  • git:clone
  • git:update
  • git:create_release
  • deploy:set_current_revision
  • deploy:symlink:release
  • deploy:log_revision

後半はこちらです。
Rails5+Puma+Nginxな環境をCapistrano3でEC2にデプロイする(後編)

おまけ

エラーログをちゃんと読めばだいたいすぐに解決すると思うが、念のため想定されるエラーと解決方法を載せておく。

1. 権限がなくscpできない

cap aborted!
SSHKit::Runner::ExecuteError: Exception while executing as deploy@xx.xxx.xxx.xxx: scp: /tmp/git-ssh-xxx-xxx-production-xxx.sh: Permission denied

→ ローカルから本番環境にscpでデプロイ実行ファイルを配置しようとしたときにPermission deniedでこけてる。別のユーザ(ec2-user)などですでにscpでファイルがつくられいる状態で、デプロイユーザ(deploy)でscpしようとしたときなどに起こる。 ls -la /tmp/ などでファイルを確認してすでに存在すれば削除する。

2. gitが入っていない

cap aborted!
SSHKit::Runner::ExecuteError: Exception while executing as deploy@xx.xxx.xxx.xxx: git exit status: 127
git stdout: Nothing written
git stderr: /usr/bin/env: git: No such file or directory

→ gitが入っていないよ。とおこられている。素直に入れる。
$ sudo yum install git

3. 権限がなくGithubに接続できない

cap aborted!
SSHKit::Runner::ExecuteError: Exception while executing as deploy@xx.xxx.xxx.xxx: git exit status: 128
git stdout: Nothing written
git stderr: Warning: Permanently added 'github.com,xxx.xx.xxx.xxx' (RSA) to the list of known hosts.
Permission denied (publickey).
fatal: Could not read from remote repository.

→ 権限がなくてリポジトリが見れないよ。とおこられている。正しい鍵が登録されているか、AgentFowardの設定は正しいかといった点を確認する。

4. 権限がなくディレクトリが作成できない

cap aborted!
SSHKit::Runner::ExecuteError: Exception while executing as deploy@xx.xxx.xxx.xxx: mkdir exit status: 1
mkdir stdout: Nothing written
mkdir stderr: mkdir: cannot create directory ‘/var/www/my-app-name/shared’: Permission denied
mkdir: cannot create directory ‘/var/www/my-app-name/releases’: Permission denied

→ 権限がなくて /var/www/my-app-name/ 配下に必要なディレクトリ(/shared/releases)が作成できないよ。とおこられている。
$ sudo chown deploy:deploy -R /var/www/my-app-name

参考

続きを読む

ローカルのデータベースをAWS EC2インスタンス内にインポートする(Capistranoによる自動デプロイで)

ローカルのデータベースをAWSにインポートしたい!

ローカルで作ったアプリをAWSのEC2インスタンス内へデプロイ。その際、ローカルで使っていたデータベースとデプロイ時のデータベースの内容を同じにしたい。つまり、○○_developmentの内容を○○_productionに反映させたい。

あ、ちなみにアプリはRuby on Rails使用で、デプロイはgem Capistranoで自動デプロイしてます。

EC2インスタンスにMySQLをインストールする

MySQLのインストールと起動

以下のコマンドでEC2インスタンスへMySQLをインストール。Amazon Linuxを利用している場合、yumというコマンドでMySQLをインストールできる。

[ec2-user@ip-xxx-xx-xx-xxx ~]$ sudo yum install mysql56-server mysql56-devel mysql56

これでMySQLのバージョン5.6がインストールされます。

MySQLを起動するためにserviceコマンドを叩く。これは、Amazon LinuxやCentOSに含まれているもので、インストールしたソフトウェアの起動を一括して行えるツール。

[ec2-user@ip-xxx-xx-xx-xxx ~]$ sudo service mysqld start

mysql ではなく mysqld であることに注意。「d」はLinuxの用語で「サーバ」を意味する「デーモン(daemon)」の頭文字。
起動確認のために以下のコマンド。

[ec2-user@ip-xxx-xx-xx-xxx ~]$ sudo service mysqld status
mysqld (pid  15692) is running...

runningと表示されれば、MySQLの起動は成功している。

パスワードの設定

yum でインストールしたMySQLには、デフォルトで root というユーザーでアクセス出来るようになっているが、パスワードが設定されていない。

以下のコマンドでパスワードを設定

[ec2-user@ip-xxx-xx-xx-xxx ~]$ sudo /usr/libexec/mysql56/mysqladmin -u root password '<設定したいパスワード>'

MySQLへの接続確認

先ほど入力したパスワードが使えるか、以下のコマンドで確認。

[ec2-user@ip-xxx-xx-xx-xxx ~]$ mysql -u root -p

Enter password: とパスワードを入力するように表示されるので、先ほど登録したパスワードを入力。以下のように表示されれば、MySQLの設定は終了。

Welcome to the MySQL monitor.  Commands end with ; or g.
Your MySQL connection id is 4
Server version: 5.6.33 MySQL Community Server (GPL)

Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or 'h' for help. Type 'c' to clear the current input statement.

mysql>

ローカルのデータベースをAWS EC2インスタンス内にインポートする

ローカルのデータベースをCSV形式でエクスポートする

まずはローカルのデータベースをCSV形式でエクスポートする。テーブル名.csvの形式でデスクトップへ出力される。

参考
MySQLのデータインポート・エクスポート
MySQLのデータベースをまるっとお引越し。 (エクスポート/インポート)

csvファイルをdbフォルダに入れる

先ほどデスクトップに出力されたcsvファイルを、(アプリ名)/dbの中に入れる。orders, users,productsのテーブルデータをエクスポートしたのなら、こんな具合になる。
image

seeds.rbを編集する

dbフォルダ下にあるseeds.rbファイル(ちょうど上の画像で選択されてるやつ)を以下のように書き変える。

seeds.rb
require "csv"
# 1番上に1度だけ記述 

# 以下は各テーブルごとに名前を変えて記述。例えばこれはordersテーブル。
orders_csv = CSV.readlines("db/orders.csv")
orders_csv.shift
orders_csv.each do |row|
  Order.create(user_id: row[1], created_at: row[2], updated_at: row[3], product_count: row[4], product_id: row[5])
  # idを除くカラム名を記述する
end

# productsテーブル
products_csv = CSV.readlines("db/products.csv")
products_csv.shift
# 以下略

deploy.rbを編集する

次に、deploy.rbを編集する。

config/deploy.rb
# 前略
set :log_level, :debug

after 'deploy:publishing', 'deploy:restart'
namespace :deploy do
# 以下を追加
  desc 'db_seed'
  task :db_seed do
    on roles(:db) do |host|
      with rails_env: fetch(:rails_env) do
        within current_path do
          execute :bundle, :exec, :rake, 'db:seed'
        end
      end
    end
  end
# ここまでが追加分
  task :restart do
    invoke 'unicorn:restart'
  end
end

リモートリポジトリへプッシュ

いつものように、git add, commit, push。

Cap deploy

capistranoを使った自動デプロイ。
まずはいつもの。

ローカル
$ bundle exec cap production deploy

これで一旦デプロイしたあと、改めてデータベース読み込み。

ローカル
$ bundle exec cap production deploy:db_seed

これで○○_development○○_productionの内容を同じものにできました!わーい!!

ちゃんとデータ入ってるのか確認

EC2インスタンスのMySQLへログイン

[ec2-user@ip-xxx-xx-xx-xxx ~]$ mysql -u root -p

パスワードを求められるので入力。

データベース一覧を確認するにはこのコマンド。

mysql> show databases

データベースを選択

mysql> use amazon_production;

各テーブルの中身を見る

# ordersテーブルなら
mysql> select * from orders

続きを読む

Fresh Install bitnami redmine stack on AWS, then migrate old data and database from old instance.

Fresh Install bitnami redmine stack on AWS, then migrate old data and database from old instance.

目的: Redmine のバージョンアップ と HTTPS化

ですが、新環境の構築手順のみやっていただければ新規構築手順としても使えます。

  • 前回書いた記事から1年ちょっと経過しました。
  • bitnami redmine stack AMI のバージョンも以下のように変化しました。(2017/06/21 現在)
    • Old version 3.2.1
    • New version 3.3.3
  • 前回は GUI でぽちぽち作成しましたが、今回は AWS CLI を中心に進めます。
  • ついでに前回書いてなかった HTTPS化 についても簡単に追記します。
  • 以下の AWS の機能を利用します。
    • Route53: ドメイン名取得、名前解決(DNS)
    • ACM(Amazon Certificate Manager): 証明書発行
    • ELB(Elastic Load Balancer): 本来は複数インスタンスをバランシングする用途に使うものですが今回は EC2 インスタンス 1台 をぶら下げ、ACM で取得した証明書を配布し外部との HTTPS通信 のために利用します。

注意と免責

  • 無料枠でない部分は料金が発生します。
  • データの正常な移行を保証するものではありません。

前提

  • 現環境が正常に動作していること。
  • 新環境を同一リージョン、同一VPC、同一サブネット内に新たにたてます。
    • インスタンス間のデータ転送を SCP で簡易に行いたいと思います。
    • 適宜セキュリティグループを解放してください。
  • aws cli version
% aws --version
aws-cli/1.11.47 Python/2.7.12 Darwin/16.6.0 botocore/1.5.10

段取り

  • 大まかに以下の順序で進めます
  1. Version 3.3.3 の AMI を使って EC2 インスタンスを起動
  2. Version 3.2.1 のデータバックアップ
    • Bitnami Redmine Stack の停止
    • MySQL Dump 取得
  3. Version 3.3.3 へのデータ復元
    • Bitnami Redmine Stack の停止
    • MySQL Dump 復元
    • Bitnami Redmine Stack の開始
  4. 動作確認

参考資料

作業手順

1. Newer Bitnami redmine stack インスタンス作成

以下の条件で作成します。

  • Common conditions

    • AMI: ami-15f98503
    • Type: t2.micro
    • Public IP: あり
  • User defined conditions
    • Region: N.Virginia
    • Subnet: subnet-bd809696
    • Security Group: sg-5b5b8f2a
    • Keypair: aws-n.virginia-default001
    • IAM Role: ec2-001
    • EBS: 20GB

WEB GUI から作るも良し、AWS CLI から作るも良し
以下コマンド実行例

set-env
KEY_NAME=aws-nvirginia-default001.pem
echo $KEY_NAME
check-ami
aws ec2 describe-images \
    --filters "Name=image-id,Values=ami-15f98503"
check-ami-name
aws ec2 describe-images \
    --filters "Name=image-id,Values=ami-15f98503" \
    | jq ".Images[].Name" \
    | grep --color redmine-3.3.3
create-instance
aws ec2 run-instances \
    --image-id ami-15f98503 \
    --count 1 \
    --instance-type t2.micro \
    --key-name aws-n.virginia-default001 \
    --security-group-ids sg-5b5b8f2a \
    --subnet-id subnet-bd809696 \
    --block-device-mappings "[{\"DeviceName\":\"/dev/sda1\",\"Ebs\":{\"VolumeSize\":20,\"DeleteOnTermination\":false}}]" \
    --iam-instance-profile Name=ec2-001 \
    --associate-public-ip-address
set-env
INSTANCE_ID=i-0f8d079eef9e5aeba
echo $INSTANCE_ID
add-name-tag-to-instance
aws ec2 create-tags --resources $INSTANCE_ID \
    --tags Key=Name,Value=redmine-3.3.3

注意書きにもありますが以下に表示される MySQL Database の root パスワードは初期起動時にしか表示されません。
このときに保管しておくか MySQL のお作法にしたがって変更しておいても良いでしょう

check-instance-created
aws ec2 describe-instances --filter "Name=instance-id,Values=$INSTANCE_ID"
wait-running-state
aws ec2 describe-instances \
    --filter "Name=instance-id,Values=$INSTANCE_ID" \
    | jq '.Reservations[].Instances[].State["Name"]'
get-redmine-password
aws ec2 get-console-output \
    --instance-id $INSTANCE_ID \
    | grep "Setting Bitnami application password to"
get-publicip
aws ec2 describe-instances \
    --filter "Name=instance-id,Values=$INSTANCE_ID" \
    | jq '.Reservations[].Instances[].NetworkInterfaces[].Association'
set-env
PUBLIC_IP=54.243.10.66
echo $PUBLIC_IP
site-check
curl -I http://$PUBLIC_IP/
HTTP/1.1 200 OK
(snip)
ssh-connect
ssh -i .ssh/$KEY_NAME bitnami@$PUBLIC_IP
first-login
bitnami@new-version-host:~$ sudo apt-get update -y
bitnami@new-version-host:~$ sudo apt-get upgrade -y
bitnami@new-version-host:~$ cat /etc/lsb-release
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=14.04
DISTRIB_CODENAME=trusty
DISTRIB_DESCRIPTION="Ubuntu 14.04.5 LTS"
bitnami@new-version-host:~$ sudo ./stack/ctlscript.sh status
subversion already running
php-fpm already running
apache already running
mysql already running
bitnami@new-version-host:~$ sudo ./stack/ctlscript.sh help
usage: ./stack/ctlscript.sh help
       ./stack/ctlscript.sh (start|stop|restart|status)
       ./stack/ctlscript.sh (start|stop|restart|status) mysql
       ./stack/ctlscript.sh (start|stop|restart|status) php-fpm
       ./stack/ctlscript.sh (start|stop|restart|status) apache
       ./stack/ctlscript.sh (start|stop|restart|status) subversion

help       - this screen
start      - start the service(s)
stop       - stop  the service(s)
restart    - restart or start the service(s)
status     - show the status of the service(s)

2. 旧バージョンのバックアップ取得

login_to_oldversion
Welcome to Ubuntu 14.04.3 LTS (GNU/Linux 3.13.0-74-generic x86_64)
       ___ _ _                   _
      | _ |_) |_ _ _  __ _ _ __ (_)
      | _ \ |  _| ' \/ _` | '  \| |
      |___/_|\__|_|_|\__,_|_|_|_|_|

  *** Welcome to the Bitnami Redmine 3.2.0-1         ***
  *** Bitnami Wiki:   https://wiki.bitnami.com/      ***
  *** Bitnami Forums: https://community.bitnami.com/ ***
Last login: Sun May 29 07:33:45 2016 from xxx.xxx.xxx.xxx
bitnami@old-version-host:~$
check-status
bitnami@old-version-host:~$ sudo stack/ctlscript.sh status
subversion already running
php-fpm already running
apache already running
mysql already running
stop
bitnami@old-version-host:~$ sudo stack/ctlscript.sh stop
/opt/bitnami/subversion/scripts/ctl.sh : subversion stopped
Syntax OK
/opt/bitnami/apache2/scripts/ctl.sh : httpd stopped
/opt/bitnami/php/scripts/ctl.sh : php-fpm stopped
/opt/bitnami/mysql/scripts/ctl.sh : mysql stopped
start-mysql
bitnami@old-version-host:~$ sudo stack/ctlscript.sh start mysql
170621 10:04:34 mysqld_safe Logging to '/opt/bitnami/mysql/data/mysqld.log'.
170621 10:04:34 mysqld_safe Starting mysqld.bin daemon with databases from /opt/bitnami/mysql/data
/opt/bitnami/mysql/scripts/ctl.sh : mysql  started at port 3306
check-available-filesystem-space
bitnami@old-version-host:~$ df -h /
Filesystem                                              Size  Used Avail Use% Mounted on
/dev/disk/by-uuid/6cdd25df-8610-4f60-9fed-ec03ed643ceb  9.8G  2.7G  6.6G  29% /
load-env-setting
bitnami@old-version-host:~$ . stack/use_redmine
bitnami@old-version-host:~$ echo $BITNAMI_ROOT
/opt/bitnami
dump-mysql
bitnami@old-version-host:~$ mysqldump -u root -p bitnami_redmine > redmine_backup.sql
Enter password:
bitnami@old-version-host:~$ ls -ltrh
  • scp 準備

手元の作業PCから新Redmine環境へssh接続するときに使用した証明書(pem)ファイルを旧Redmine環境にも作成します。

  • 今回は作業PC上で cat で表示させておいて旧環境のコンソール上にコピペしました。
example
bitnami@old-version-host:~$ vi .ssh/aws-nvirginia-default001.pem
bitnami@old-version-host:~$ chmod 600 .ssh/aws-nvirginia-default001.pem
  • ファイル転送
file_transfer
bitnami@old-version-host:~$ scp -i .ssh/aws-nvirginia-default001.pem redmine_backup.sql <new-version-host-ipaddr>:~
  • 新バージョン側にファイルが届いているか確認
check-transfered-files
bitnami@new-version-host:~$ ls -alh redmine*

3. 新バージョンへの復元

stop-stack
bitnami@new-version-host:~$ sudo stack/ctlscript.sh status
subversion already running
php-fpm already running
apache already running
mysql already running

bitnami@new-version-host:~$ sudo stack/ctlscript.sh stop

/opt/bitnami/subversion/scripts/ctl.sh : subversion stopped
Syntax OK
/opt/bitnami/apache2/scripts/ctl.sh : httpd stopped
/opt/bitnami/php/scripts/ctl.sh : php-fpm stopped
/opt/bitnami/mysql/scripts/ctl.sh : mysql stopped
start-mysql
bitnami@new-version-host:~$ sudo stack/ctlscript.sh start mysql
initial-database
bitnami@new-version-host:~$ mysql -u root -p
Enter password:
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 1
Server version: 5.6.35 MySQL Community Server (GPL)

(snip)

mysql> drop database bitnami_redmine;

mysql> create database bitnami_redmine;

mysql> grant all privileges on bitnami_redmine.* to 'bn_redmine'@'localhost' identified by 'DATAB
ASE_PASSWORD';

mysql> quit
restore-dumpfile
bitnami@new-version-host:~$ mysql -u root -p bitnami_redmine < redmine_backup.sql
Enter password:
bitnami@new-version-host:~$
edit-line-18
bitnami@new-version-host:~$ vi /opt/bitnami/apps/redmine/htdocs/config/database.yml

    18    password: "DATABASE_PASSWORD"
db-migrate
bitnami@new-version-host:~$ cd /opt/bitnami/apps/redmine/htdocs/
bitnami@new-version-host:/opt/bitnami/apps/redmine/htdocs$ ruby bin/rake db:migrate RAILS_ENV=production
bitnami@new-version-host:/opt/bitnami/apps/redmine/htdocs$ ruby bin/rake tmp:cache:clear
bitnami@new-version-host:/opt/bitnami/apps/redmine/htdocs$ ruby bin/rake tmp:sessions:clear
stack-restart
bitnami@new-version-host:/opt/bitnami/apps/redmine/htdocs$ cd
bitnami@new-version-host:~$ sudo stack/ctlscript.sh restart

bitnami@new-version-host:~$ exit
site-check
curl -I http://$PUBLIC_IP/
HTTP/1.1 200 OK
(snip)

ブラウザでも http://$PUBLIC_IP/ でアクセスして旧環境のユーザー名とパスワードでログイン出来ることを確認してください。

この時点で旧環境のインスタンスを停止させておいて良いでしょう。
いらないと判断した時に削除するなりしてください。

4. おまけ HTTPS化

  • 4-1. Route53 でドメイン名を取得してください

    • .net で 年額 11 USドル程度ですので実験用にひとつくらい維持しておくと便利
  • 4-2. Certificate Manager で証明書を取得します
    • コマンドでリクエストしてます
aws acm request-certificate --domain-name redmine.hogefuga.net
check-status-pending
aws acm describe-certificate \
    --certificate-arn "arn:aws:acm:us-east-1:942162428772:certificate/fdf099f9-ced7-4b97-a5dd-f85374d7d112" \
    | jq ".Certificate.Status"
"PENDING_VALIDATION"
  • 4-3. 承認する

    • ドメインに設定しているアドレスにメールが飛んできます
  • 4-4. ステータス確認
check-status-ISSUED
aws acm describe-certificate \
    --certificate-arn "arn:aws:acm:us-east-1:942162428772:certificate/fdf099f9-ced7-4b97-a5dd-f85374d7d112" \
    | jq ".Certificate.Status"
"ISSUED"
  • 4-5. Classic タイプの HTTPS ELB をつくる
example
aws elb create-load-balancer \
    --load-balancer-name redmine-elb1 \
    --listeners "Protocol=HTTPS,LoadBalancerPort=443,InstanceProtocol=HTTP,InstancePort=80,SSLCertificateId=arn:aws:acm:us-east-1:942162428772:certificate/fdf099f9-ced7-4b97-a5dd-f85374d7d112" \
    --availability-zones us-east-1a \
    --security-groups sg-3c90f343
  • 4-6. インスタンスをくっつける
example
aws elb register-instances-with-load-balancer \
    --load-balancer-name redmine-elb1 \
    --instances i-0f8d079eef9e5aeba
  • 4-7. State が InService になるまで待ちます
example
aws elb describe-instance-health \
    --load-balancer-name redmine-elb1
  • 4-8. DNS Name を確認する(4-10. で使います)
example
aws elb describe-load-balancers \
    --load-balancer-name redmine-elb1 \
  | jq ".LoadBalancerDescriptions[].DNSName"
  • 4-9. 今の設定を確認
example
aws route53 list-resource-record-sets \
    --hosted-zone-id Z3UG9LUEGNT0PE | jq .
  • 4-10. 投入用の JSON をつくる
example
vi change-resource-record-sets.json
example
{
  "Comment": "add CNAME for redmine.hogefuga.net",
  "Changes": [
    {
      "Action": "CREATE",
      "ResourceRecordSet": {
        "Name": "redmine.hogefuga.net",
        "Type":"CNAME",
        "TTL": 300,
        "ResourceRecords": [
          {
            "Value": <DNSName>
          }
        ]
      }
    }
  ]
}

4-11. 設定投入

example
aws route53 change-resource-record-sets \
    --hosted-zone-id Z3UG9LUEGNT0PE \
    --change-batch file://change-resource-record-sets.json

4-12. 設定確認

example
aws route53 list-resource-record-sets \
    --hosted-zone-id Z3UG9LUEGNT0PE

4-13. ブラウザ確認

https://redmine.hogefuga.net

4-14. EC2 インスタンスのセキュリティグループ再設定

  • グローバルの TCP:80 削除
  • サブネット内の TCP:80 許可
check
aws ec2 describe-security-groups --group-ids sg-b7d983c8
change
aws ec2 modify-instance-attribute \
    --instance-id i-0f8d079eef9e5aeba \
    --groups sg-b7d983c8

4-15. 再度ブラウザからアクセス可能か確認

続きを読む

Mastodonインスタンス構築(鯖:AWS EC2、ドメイン:お名前.com、SSL:Let’s Encrypt)

まずは

QiitaはROM専(死語?)だったので初投稿。
こちらの記事に勇気付けられた。

「僕が書いたことはみんな書いている、ハマっていることは共有しなくてもいい」という考えも浮かぶと思うが…
・情報鮮度の観点で出す価値あり

http://qiita.com/hinom77/items/dfa9e0c734e47271edb7

たしかにググって記事がたくさん出てくると学んでて損はない技術なんだろうと思えてくる。
ビッグウェーブに乗りたいというのもある。
というわけで何番煎じかわからないがマストドンのインスタンス構築記録を書く。
見せ方、引用の仕方など作法があればご容赦。
Qiitaのマークダウンすらままならず…。

基本的な軸

基本的には↓↓を参考にさせていただきました。
私の環境で違ったところだけ横道に反れたりしながら追記してます。
基本は参考URLを見ていただき、たまにこっちに戻ってくるという感じがよいかと。
※以降【】でかこっている中項目は下記参考先の中項目タイトルに準じています。

■マストドンAWS構築チュートリアル完全版|初心者から大規模運用まで 5.お手軽な手順
http://webfood.info/mastodon-aws-tutorial/#section-5

【EC2インスタンスの作成】

インスタンススペックはt2.microを選択。
無料枠で選択できたので。

【Route53でHosted Zoneを作る】

丸々飛ばし。
DNSはお名前.comに任せる。

AWS EC2のインスタンスに固定グローバルIPを付与

AWSでは固定グローバルIP=Elastic IPと呼ばれている。
↓↓に書かれている通りに沿って進める。

■AWS EC2インスタンスにElastic IP(固定グローバルIPアドレス)を割り当てる
https://ac-5.net/aws/aws_elasticip_allocation

AWSのElastic IPを独自ドメインと関連付ける

DNSの設定。関連付ける、という言葉が正しいのかどうか。

■(お名前.com)ネームサーバーのAレコード設定
http://rensrv.com/domain/onamae-com/a_record-setting-onamae-com/

【SSHでログインする】

そのまま。

【Let’s EncryptでSSL証明書を取得する】

$ ./certbot-autoの箇所で途中、エラーで正常終了しなかった。

Requesting root privileges to run certbot...
/home/ubuntu/.local/share/letsencrypt/bin/letsencrypt
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Failed to find executable apache2ctl in PATH: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin
Certbot doesn't know how to automatically configure the web server on this system. However, it can still get a certificate for you. Please run "certbot-auto certonly" to do so. You'll need to manually configure your web server to use the resulting certificate.

apache2の起動コマンド(?)が見つからないようだ。
そもそもデフォルトでインストールされていないぽい。
↓↓
●対応:apache2インストール→再度実行

$ sudo apt-get update
$ sudo apt-get install apache2
$ ./certbot-auto

結果としてこれで成功したが、完了までにいろいろ聞かれたので参考までに記載。

●ドメイン名を入力してくれー
No names were found in your configuration files. Please enter in your domain
name(s) (comma and/or space separated) (Enter ‘c’ to cancel):

自前のドメイン名を入力して、エンター。

●HTTPSのみの接続にする?
Please choose whether HTTPS access is required or optional.
——————————————————————————-
1: Easy – Allow both HTTP and HTTPS access to these sites
2: Secure – Make all requests redirect to secure HTTPS access
——————————————————————————-
Select the appropriate number [1-2] then enter:

2の方が無難かと考え、2を入力してエンター。

●成功の確認
——————————————————————————-
Congratulations! You have successfully enabled https://(設定したドメイン)

You should test your configuration at:
https://www.ssllabs.com/ssltest/analyze.html?d=(設定したドメイン)
——————————————————————————-

一応言われている通りにアクセスしたら、A評価(多少時間かかる)。

【ミドルウェアの設定】

t2.microなのでスワップ設定は飛ばし。

と思ったら後ほど出てくるdocker-composeでひっかかった。
処理が途中で止まってしまうのだが、どうやらメモリ不足が原因らしい…。

$docker-compose run --rm web rails assets:precompile

http://uyamazak.hatenablog.com/entry/2017/05/22/151210

たしかにスワップの設定後、再トライしたら処理が完了できた。

あと、念のためnginxの編集前の設定ファイルをコピーして残しておく。

cp /etc/nginx/sites-available/default /etc/nginx/sites-available/default.ort

【マストドンのセットアップ】

ここでだいぶ時間を食った…。

Docker動いてない?

ERROR: Couldn’t connect to Docker daemon at http+docker://localunixsocket – is it running?

●いろいろ対応:
・鯖再起動←たぶん関係ない。
・pip3のupgrade←アップグレードは成功したがたぶん関係ない。
 ただ、一応やったことなので残しておく。

$sudo pip3 install --upgrade pip

・インストール済かの確認

$pip3 list
docker-compose (1.13.0)

結局よくわからず↓↓を参考に入れ直す。

■今何かと話題のマストドン(mastodon)鯖を自分用に無料で立てる方法
【必要なものをインストールする】のセクション
http://jtwp470.hatenablog.jp/entry/2017/04/15/174036

その後、再度実行→成功!

$ sudo docker-compose build

以降、

$ sudo docker-compose run --rm web rake secret

から続行。
以降、assetsのdocker-composeで躓くも何とかAbout画面表示までこぎ着けた…。
まずは一旦の達成感。

【メールの設定】

今回はとりあえず自分のテスト用鯖なのでSESの制限は解除しない。
他はそのまま。

【cronの設定】

今回参照させていただいているところはマストドンのインストールディレクトリを指定しているのでcron内のパスを修正。
/home/ubuntu/mastodon→/home/ubuntu/live
他はそのまま。

ログインと管理画面

最後に、今回はとりあえず個人用インスタンスということにしているのでユーザ認証は手動で実行。
ということで↓↓を参考にさせていただきました。

■今何かと話題のマストドン(mastodon)鯖を自分用に無料で立てる方法
【初期登録と管理画面をだす方法】【管理画面の出し方】
http://jtwp470.hatenablog.jp/entry/2017/04/15/174036

なぜか手動認証のコマンドを打っても自前のgmailアカウントが見つからないと言われたので、適当な捨てアドを作り、登録し、管理画面から認証するという手順を踏みました。

さいごに

最初は探り探りだったので時間としては朝から晩までかかりました。
2回目はこの手順を残しておいたので2時間強くらいでできました。
1回目構築終わったあと、疲れなのか何なのかAWSのインスタンを消去してしまい、朝起きたときは絶望しましたが逆にこの手順が間違ってなかったことを自分で証明できてよかったよかった(?)
インスタンス構築にあたり最近の技術も勉強できたのでそれもよかった。
Dockerのことがまだはっきりと理解しきれていないので引き続き勉強ですね。

最後になりましたが、参考にさせていただいた先人たちには多大なる感謝を。
またこの記事がこれからの誰かの役に立てれば幸いです。

参考サイトまとめ

■マストドンAWS構築チュートリアル完全版|初心者から大規模運用まで
http://webfood.info/mastodon-aws-tutorial/
■AWS EC2インスタンスにElastic IP(固定グローバルIPアドレス)を割り当てる
https://ac-5.net/aws/aws_elasticip_allocation
■(お名前.com)ネームサーバーのAレコード設定
http://rensrv.com/domain/onamae-com/a_record-setting-onamae-com/
■今何かと話題のマストドン(mastodon)鯖を自分用に無料で立てる方法
http://jtwp470.hatenablog.jp/entry/2017/04/15/174036

続きを読む

AmznLinuxのRedmine 3.2を3.3にアップデートしてみた

はじめに

以前インストールしていたredmineを再活用するにあたり、最新のバージョン3.3に更新してみた手順です。環境は、Apache 2.4 + Passanger + ruby 2.2 + Redmine on AmazonLinux。

Redmine 3.3 のインストール

現状、/var/lib/redmine にインストールされているので、別ディレクトリにダウンロードして、シンボリックリンクで差し替える方法で進める。

ダウンロード

svn を使って、/var/lib/redmine-3.3 以下にダウンロードします

cd /usr/lib/
svn co https://svn.redmine.org/redmine/branches/3.3-stable redmine-3.3

設定の移行

特に変更はないので設定ファイルをそのままコピー

cp -p redmine/config/database.yml redmine-3.3/config/
cp -p redmine/config/configuration.yml  redmine-3.3/config/

プラグイン/ファイル類のコピー移行

アップロードファイル/プラグイン/テーマも丸ごとコピー。同一ファイルがある場合、上書きはしないようにした

cp -rp redmine/files/* redmine-3.3/files/
cp -rp redmine/plugins/* redmine-3.3/plugins/
cp -rp redmine/public/themes/* redmine/3.3/public/themes/

ファイルオーナーの変更

# 最初から apache ユーザでファイルを作っておいた方が良かった

sudo chown -R apache:apache redmine-3.3

gemのインストール

cd redmine-3.3/
sudo -u apache gem install bundler --no-rdoc --no-ri
sudo -u apache bin/bundle install --without development test

bundle install で、uuid.hがないというエラーメッセージが出たので、yum install libuuid-devel 後再実行。

セッション鍵の作成もしておく

sudo -u apache bin/bundle exec rake generate_secret_token

今回、bundle exec rake が見つからないというエラーが出たが、色々悩んだ挙句、全てユーザ apache で再実行していくと回避できた。

プラグイン/テーマのアップデート

必要に応じて新しいバージョンに更新する。

ディレクトリ事削除して再取得するなどで一式を更新する。git clone で取得した場合は pull するだけでOK。

cd plugins/redmine_dmsf
git pull

データベースの更新

プラグインの更新も忘れずに

sudo -u apache bin/bundle exec rake db:migrate RAILS_ENV=production
sudo -u apache bin/bundle exec rake redmine:plugins:migrate RAILS_ENV=production

シンボリックリンクの変更

apache-passengerの設定は変えずに、ディレクトリだけ変更する

cd /var/lib
sudo mv redmine redmine-3.2
sudo ln -s redmine-3.3 redmine

動作確認

まずは、キャッシュをクリアし、apacheを再起動。

bundle exec rake tmp:cache:clear tmp:sessions:clear
sudo /etc/init.d/httpd graceful

ブラウザでアクセスし、上部バーの「管理」→「情報」で、Redmine のバージョンが3.3.X になっていることを確認。

最後に

bundle exec rake のエラーに時間がかかってしまい、根本原因はいまだ不明なので、もやもやが晴れない。

続きを読む

初心者向け:AWS(EC2)にRailsのWebアプリをデプロイする方法 ⑤

参考

  • 以下の記事を参考にさせて頂きました。ありがとうございます。

0から始めるAWS入門③:ELB編

目次はこちら

初心者向け:AWS(EC2)にRailsのWebアプリをデプロイする方法 目次

手順

ロードバランサーの作成

左側のリストから、ロードバランサーを選択します。

スクリーンショット 2017-05-27 20.32.35.png

「ロードバランサーの作成」をクリックします。

スクリーンショット 2017-05-27 20.34.13.png

以下が表示されます。

スクリーンショット 2017-05-27 20.35.12.png

今回は、「標準ロードバランサー」を選択します。

スクリーンショット 2017-05-27 20.35.47.png

「次へ」をクリックします。

スクリーンショット 2017-05-27 20.36.36.png

赤囲みの部分を入力します。

スクリーンショット 2017-05-27 20.37.26.png

スクリーンショット 2017-05-27 20.38.55.png

赤丸の部分をクリックします。

スクリーンショット 2017-05-27 20.42.06.png

以下のように設定されます。

スクリーンショット 2017-05-27 20.42.45.png

「次の手順:セキュリティグループの割り当て」をクリックします。

スクリーンショット 2017-05-27 20.43.57.png

作成したセキュリティグループを選択します。

スクリーンショット 2017-05-27 20.45.38.png

「次の手順:セキュリティ設定の構成」をクリックします。

スクリーンショット 2017-05-27 20.46.22.png

何もせず、「次の手順:ヘルスチェックの設定」をクリックします。

スクリーンショット 2017-05-27 20.48.02.png

①〜③を設定します。

スクリーンショット 2017-05-27 20.52.23.png

スクリーンショット 2017-05-27 20.55.09.png

「次の手順:EC2インスタンスの追加」をクリックします。

スクリーンショット 2017-05-27 20.56.00.png

作成したインスタンスを選択します。

スクリーンショット 2017-05-27 20.57.16.png

「次の手順:タグの追加」をクリックします。

スクリーンショット 2017-05-27 20.58.12.png

キーに Name 、値に アプリ名-Webserver と入力します。

スクリーンショット 2017-05-27 20.59.54.png

ChristChurches-Map-Webserver

「確認と作成」をクリックします。

スクリーンショット 2017-05-27 21.00.46.png

「作成」をクリックします。

スクリーンショット 2017-05-27 21.01.58.png

「閉じる」をクリックします。

スクリーンショット 2017-05-27 21.02.43.png

作成したロードバランサーを選択し、インスタンスをクリックします。

スクリーンショット 2017-05-27 21.03.26.png

状態が、InService になっていたらOKです。

もしなっていなかったら、リロードしてください。

それでもなっていなかったら、何かしらの問題があります。

スクリーンショット 2017-05-28 0.57.47.png

Railsアプリの起動

ディレクトリの場所を確認します。

$ pwd
/var/www/projects/アプリ名

プリコンパイルを実行します。

$ bundle exec rake assets:precompile RAILS_ENV=production

Nginxを再起動します。

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

Unicornを起動します。

$ bundle exec unicorn_rails -c /var/www/projects/アプリ名/config/unicorn.conf.rb -D -E production

$ bundle exec unicorn_rails -c /var/www/projects/christchurches-map/config/unicorn.conf.rb -D -E production

Uniconの起動を確認します。

$ ps -ef | grep unicorn | grep -v grep
501       3802     1  5 16:02 ?        00:00:01 unicorn_rails master -c /var/www/projects/christchurches-map/config/unicorn.conf.rb -D -E production
501       3805  3802  0 16:02 ?        00:00:00 unicorn_rails worker[0] -c /var/www/projects/christchurches-map/config/unicorn.conf.rb -D -E production
501       3807  3802  0 16:02 ?        00:00:00 unicorn_rails worker[1] -c /var/www/projects/christchurches-map/config/unicorn.conf.rb -D -E production

ブラウザから表示を確認します。

http://IPアドレス/

http://52.192.101.190/

画面に表示されればOKです。

スクリーンショット 2017-05-29 21.18.04.png

以上で、IPアドレスによるデプロイは完了しました。

ここからは、ドメインを適用する方法を紹介します。

以下に続きます。

初心者向け:AWS(EC2)にRailsのWebアプリをデプロイする方法 ⑥

続きを読む