aws周りのメモ2

postgresqlを使う

RDSへpostgresqlをいれて立ち上げ

認証と接続

import-key-pair — AWS CLI 1.11.87 Command Reference
http://docs.aws.amazon.com/cli/latest/reference/ec2/import-key-pair.html

cd $HOGE
openssl genrsa -out my-key.pem 2048
openssl rsa -in my-key.pem -pubout > my-key.pub
# IAMのコンパネで*.pubを入力
# 多分、権限があれば以下でもいける
# aws iam upload-ssh-public-key

【AWS 再入門】EC2 + RDS によるミニマム構成なサーバー環境を構築してみよう – NET BIZ DIV. TECH BLOG
https://tech.recruit-mp.co.jp/infrastructure/retry-aws-minimum-vpc-server-environment/

便利

無料枠

無料のクラウドサービス | AWS 無料利用枠
https://aws.amazon.com/jp/free/

AMI

AWS Marketplace: Search Results
https://aws.amazon.com/marketplace/search/results?x=14&y=18&searchTerms=&page=1&ref_=nav_search_box

CFテンプレート

サンプルコード & テンプレート – AWS CloudFormation | AWS
https://aws.amazon.com/jp/cloudformation/aws-cloudformation-templates/

ec2 ami tool & ec2 api tool

Mac で Amazon EC2 API Toolsを設定する – サーバーワークスエンジニアブログ
http://blog.serverworks.co.jp/tech/2013/01/31/mac-amazon-ec2-api-tools-setup/

ec2 api toolは若干心配。

VPCを使う

接続の際に、sshを経由したい。sslでもいいけどなんかsshがいいなと。
パスワードよりkeyのほうがセキュアだからかな。

0から始めるAWS入門①:VPC編 – Qiita
http://qiita.com/hiroshik1985/items/9de2dd02c9c2f6911f3b

導入

Amazon VPC とは? – Amazon Virtual Private Cloud
http://docs.aws.amazon.com/ja_jp/AmazonVPC/latest/UserGuide/VPC_Introduction.html

公式のいろいろ

料金 – Amazon VPC | AWS
https://aws.amazon.com/jp/vpc/pricing/

基本は無料だけどNATとVPNは別課金。

【AWS 再入門】VPC 環境に踏み台サーバーを構築して SSH 接続してみよう – NET BIZ DIV. TECH BLOG
https://tech.recruit-mp.co.jp/infrastructure/retry-aws-bastion-host-vpc/#i-3

ec2(Bastion)を配置する必要がありそう。

【AWS 再入門】EC2 + RDS によるミニマム構成なサーバー環境を構築してみよう – NET BIZ DIV. TECH BLOG
https://tech.recruit-mp.co.jp/infrastructure/retry-aws-minimum-vpc-server-environment/

VPC に推奨されるネットワーク ACL ルール – Amazon Virtual Private Cloud
http://docs.aws.amazon.com/ja_jp/AmazonVPC/latest/UserGuide/VPC_Appendix_NACLs.html

vpcでのネットワークのポリシーの例

Default VPC

AWSのDefault VPCを削除して困った話 – MikeTOKYO Developers
http://blog.miketokyo.com/post/49939300091/aws-default-vpc

デフォルトvpcは削除したらダメか。使い分けがわからん。

Amazon EC2 と Amazon Virtual Private Cloud – Amazon Elastic Compute Cloud
http://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/using-vpc.html

基本の機能はデフォルトとそうじゃないvpcは同じだけど、
デフォルトvpcがないとちゃんと機能しない。
デフォルトの属性によって、指定がないとipを紐付けたりする。

VPCネットワーク設計

これだけ押さえておけば大丈夫!Webサービス向けVPCネットワークの設計指針 | eureka tech blog
https://developers.eure.jp/tech/vpc_networking/

ネットワークは一度稼働させると移行が大変なので、初期設計が非常に重要になります。

わかりやすい。図が特に。

  • Bastion
  • NAT
  • Security Group

ENI

インフラエンジニアに贈るAmazon VPC入門 | シリーズ | Developers.IO
http://dev.classmethod.jp/series/vpcfor-infra-engineer/

サブネットで指定したIPアドレスのうち、先頭4つと末尾の1つはVPCで予約されるため使用できません。

VPCでは常にDHCP有効とするのがポイントです。

また、DHCPサービスで伝えられる情報(DHCPオプション)は、変更することもできます。

仮想マシンにひもづくENIにより、DHCPサーバーから毎回同じMACアドレス、IPアドレスが付与されます。これは、仮想マシンの状態に依存しないため、仮想マシンを再起動しようと、一旦シャットダウンしてしばらくしてから起動した場合でも必ず同じアドレスが付与されます。

ENI(Elastic Network Interface)か。。なるほど。でも、使うことはなさそうだな。

NAT

IPマスカレードが使えないVPC
NATは、Static(静的・サーバー用途)とElastic(仮想・クライアント用途)がある。
個人的には、このNATインスタンスの実装は、あまり好きではありません。動きがややこしいですし、ユーザーが自分でNATインスタンスの管理をしなければならないのも煩雑な印象を受けます。VPCのネットワークサービスの一つとして提供される機能であれば、ユーザーからはなるべく抽象化され仮想マシンとして意識されないようにするべきと考えます。
ただ、ユーザーから仮想マシンとして見える分、機能・実装が具体的に把握できる点やカスタマイズ性が高い点は良いとも思っています。

NAT インスタンスと NAT ゲートウェイの比較 – Amazon Virtual Private Cloud
http://docs.aws.amazon.com/ja_jp/AmazonVPC/latest/UserGuide/vpc-nat-comparison.html

なるほど。。

Bastion

AWSで最低限セキュアな構成を組む – Qiita
http://qiita.com/ausuited/items/09b626fa5264f0c650fd

パブリックSubnetにEC2インスタンス(踏み台サーバーとして)
NATインスタンスを作成した要領で、パブリックSubnetにEC2インスタンスを作成する。Security groupは新規に作成してSSHをAnywhereに。Key pairは厳重に管理。尚、踏み台サーバーは、使用する時以外はStoppedにしておく事で、さらにセキュアな状態とする。このデザインパターンをOn Demand Bastionパターンと呼ぶらしい。

詳しい。「On Demand Bastionパターン」か。なるほど。

vpcへの踏み台サーバー
ポートフォワーディング、トンネルなどと同じ意味。

Network ACL

インスタンス単位じゃなくサブネット単位でより制限してセキュアにしたい場合に使うのかな。

安全なVPC設計 — Commerce Hack
http://tech.degica.com/ja/2016/01/07/designing-vpc-and-subnets/


結局どうするのか、、ひとまずNATはつかわずに、Bistionをつくってみる感じかな。

アベイラビリティーゾーン

リージョンごとでの、障害などで全部やられないように物理的にセグメントされた範囲の単位かな。
RDSではセグメントグループに2つ以上のゾーンを含める。でも、一つしか使わなくていい。ということか。s

RDSのVPC間の移動

サブネットグループの関連付けを変えればいいらしい。間違って設定したので移動した。

【小ネタ】知っていましたか?RDSを別のVPCに移動できることを | Developers.IO
http://dev.classmethod.jp/cloud/aws/rds_can_move_to_another_vpc/

Bastion作成作業をしてみる

主に下記を参考。

【AWS 再入門】EC2 + RDS によるミニマム構成なサーバー環境を構築してみよう – NET BIZ DIV. TECH BLOG
https://tech.recruit-mp.co.jp/infrastructure/retry-aws-minimum-vpc-server-environment/

  • サブネットってなんだっけとか復習。
  • ストレージはどうするのか。
    • とりあえずssdにしたけどマグネティックでよかったかなあ。

      • ssd:$0.12 : 1 か月にプロビジョニングされたストレージ 1 GB あたり
      • マグネティック: 0.05 USD/GB-月
  • public IPは設定必要だよね
  • market placeからamiを取得した方がいいの?
    • とりあえず公式のウィザードを使ったけど。
  • 認証にIAMが追加されていたので使ってみた
    • これとは別にキーペアは必要ってことかな。
  • CFnテンプレート(CloudFormationテンプレート)というのがあるらしい。。
    • これでつくりなおそうかな。。
  • サブネットとかいろいろネットワーク系の設定
    • なんだかんだいっていろいろあった
  • セキュリティグループ
    • エイリアスみたいなセキュリティグループにできたらいいのに。タグや名前で明示化かな。
    • bastionは22をあけて、rdsは5432をbastionからのみあける
  • ログイン
  • DNS
    • あれ、パブリックDNSがうまく割り振ってないな。。
      AWSでPublic DNS(パブリックDNS)が割り当てられない時の解決法 – Qiita
      http://qiita.com/sunadoridotnet/items/4ea689ce9f206e78a523
    • RDSのDNS
      • nslookupしたら内部ipがかえってくるのね。接続できないけどなんか気持ち悪いな。これかな。。
        外部からdnsを引けることを気にしている人は見かけなくて便利だからって話なのかね。
        【AWS】VPC内でPrivate DNSによる名前解決 – Qiita
        http://qiita.com/y_takeshita/items/2eb5e6abb5eb5516d1de

やってるうちはいいけど、しばらくやらないと設定の方法とか忘れそう。。こういうのは学習コストだけじゃないな。

PlantUMLで図にしておく

Kobito.hQIwJs.png

VPC内のRDSへLambdaから接続。。

しまった!アンチパターンだそうだ。。

Lambda+RDSはアンチパターン – Qiita
http://qiita.com/teradonburi/items/86400ea82a65699672ad

Lambda + RDS benchmark – Qiita
http://qiita.com/taruhachi/items/3f95ae3e84f56edb3787

新し目の記事でIAM認証でクリアできそうな。。

【全世界待望】Public AccessのRDSへIAM認証(+ SSL)で安全にLambda Pythonから接続する – サーバーワークスエンジニアブログ
https://blog.serverworks.co.jp/tech/2017/04/27/rds-iam-auth-lambda-python/


セキュアに接続するのと速度のトレードオフになっていたのが
IAM認証のおかげで両方可能になったということっぽい。
でも、ネットのスループット、コネクション数(料金・負荷)、など、、ほかにも気にすることが出て来そうで若干不安。
非同期でよければキューイングして一回投げっぱなしすればどうだろう。
もしくは、似てるけど、Lambdaから一回値を返してもらってからRDSへ投げ直す。
これでいっかなあ。。Lambdaの意味がなくなる?うーん。

今後

  • 疑問としてrdsなど内部向けのdnsを外から見れなくできないものか。
  • というか、rdsのエンドポイントって再起動したら変わったりしないかね。ipは固定されるのか。
    • たぶん、サブネット内でdhcpになるのでipは変動するけどエンドポイントは固定。。じゃないかしら。

posgresqlをつかうための情報

Amazon RDS 上の PostgreSQL – Amazon Relational Database Service
http://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/UserGuide/CHAP_PostgreSQL.html#PostgreSQL.Concepts.General.SSL

続きを読む

AWS ECSにてカスタムしたredmineのdockerイメージを動かすまでのメモ(その1)

redmineの構築、プラグインの導入をふつーにやると面倒くさい。
あと、一旦構築した後redmineのバージョンをあげるのもやっぱり面倒くさい。

→ので、dockerにてプラグインのインストールやらなにやらを手順をコード化して簡単にRedmineの導入が
できるようにしました。
なお動作環境はAWSのECS(Elastic Container Service)を使います。

大きな流れ

1.Dockerfileを用意
2.AWSにてElastic Container Service(ECS)のタスクを定義
3.ECSのインスタンスを用意

今回はまず1を用意します。

1.Dockerfileを用意

redmineの公式イメージがdockerhubにあるのでこれをもとにpluginを導入する手順を
dockerfile化していきます。

ポイントは2つです。
1.ベースのイメージはredmine:x.x.x-passengerを利用する
2.DBのマイグレーションが必要ないものはpluginsフォルダに配置し、マイグレーションが必要なものは別フォルダ(install_plugins)に配置。
→コンテナ起動時にマイグレーションを行うようdocker-entrypoint.shに記載しておきます。

インストールするプラグイン一覧

独断と偏見で入れたプラグインです。

No プラグインの名前 概要
1 gitmike githubの雰囲気のデザインテーマ
2 backlogs スクラム開発でおなじみ。ストーリーボード
3 redmine_github_hook redmineとgitを連動
4 redmine Information Plugin redmineの情報を表示可能
5 redmine Good Job plugin チケット完了したら「Good Job」が表示
6 redmine_local_avatars アイコンのアバター
7 redmine_startpage plugin 初期ページをカスタマイズ
8 clipboard_image_paste クリップボードから画像を添付できる 
9 Google Analytics Plugin 閲覧PV測定用
10 redmine_absolute_dates Plugin 日付を「XX日前」 ではなくyyyy/mm/ddで表示してくれる
11 sidebar_hide Plugin サイドバーを隠せる
12 redmine_pivot_table ピボットテーブルできる画面追加
13 redmine-slack 指定したslack channnelに通知可能
14 redmine Issue Templates チケットのテンプレート
15 redmine Default Custom Query 一覧表示時のデフォルト絞り込みが可能に
16 redmine Lightbox Plugin 2 添付画像をプレビューできる
17 redmine_banner Plugin 画面上にお知らせを出せます
18 redmine_dmsf Plugin フォルダで文書管理できる
19 redmine_omniauth_google Plugin googleアカウントで認証可能
20 redmine view customize Plugin 画面カスタマイズがコードで可能

Dockerfile

上記のプラグインをインストール済みとするためのDockerfileです。
なお、ベースイメージは最新(2017/05/19時点)の3.3.3を使用しています。

Dockerfile
FROM redmine:3.3.3-passenger
MAINTAINER xxxxxxxxxxxxxxxxx

#必要コマンドのインストール
RUN apt-get update -y 
 && apt-get install -y curl unzip ruby ruby-dev cpp gcc libxml2 libxml2-dev 
  libxslt1-dev g++ git make xz-utils xapian-omega libxapian-dev xpdf 
  xpdf-utils antiword catdoc libwpd-tools libwps-tools gzip unrtf 
  catdvi djview djview3 uuid uuid-dev 
 && apt-get clean

#timezoneの変更(日本時間)
RUN cp /usr/share/zoneinfo/Asia/Tokyo /etc/localtime
ENV RAILS_ENV production

#gitmakeテーマのインストール
RUN cd /usr/src/redmine/public/themes 
 && git clone https://github.com/makotokw/redmine-theme-gitmike.git gitmike 
 && chown -R redmine.redmine /usr/src/redmine/public/themes/gitmike



#redmine_github_hookのインストール
RUN cd /usr/src/redmine/plugins 
 && git clone https://github.com/koppen/redmine_github_hook.git

#Redmine Information Pluginのインストール
RUN curl http://iij.dl.osdn.jp/rp-information/57155/rp-information-1.0.2.zip > /usr/src/redmine/plugins/rp-information-1.0.2.zip 
 && unzip /usr/src/redmine/plugins/rp-information-1.0.2.zip -d /usr/src/redmine/plugins/ 
 && rm -f /usr/src/redmine/plugins/rp-information-1.0.2.zip

#Redmine Good Job pluginのインストール
RUN curl -L https://bitbucket.org/changeworld/redmine_good_job/downloads/redmine_good_job-0.0.1.1.zip > /usr/src/redmine/plugins/redmine_good_job-0.0.1.1.zip 
 && unzip /usr/src/redmine/plugins/redmine_good_job-0.0.1.1.zip -d /usr/src/redmine/plugins/redmine_good_job 
 && rm -rf /usr/src/redmine/plugins/redmine_good_job-0.0.1.1.zip

#redmine_startpage pluginのインストール
RUN cd /usr/src/redmine/plugins 
 && git clone https://github.com/txinto/redmine_startpage.git

#Redmine Lightbox Plugin 2 Pluginのインストール
RUN cd /usr/src/redmine/plugins 
 && git clone https://github.com/peclik/clipboard_image_paste.git

#Google Analytics Pluginのインストール
RUN cd /usr/src/redmine/plugins 
 && git clone https://github.com/paginagmbh/redmine-google-analytics-plugin.git google_analytics_plugin

#redmine_absolute_dates Pluginのインストール
RUN cd /usr/src/redmine/plugins 
 && git clone https://github.com/suer/redmine_absolute_dates

#sidebar_hide Pluginのインストール
RUN cd /usr/src/redmine/plugins 
 && git clone https://github.com/bdemirkir/sidebar_hide.git

#redmine_pivot_tableのインストール
RUN cd /usr/src/redmine/plugins 
 && git clone https://github.com/deecay/redmine_pivot_table.git

#redmine-slackのインストール用モジュールを用意(インストールはredmine起動時に実施)
RUN cd /usr/src/redmine/install_plugins 
 && git clone https://github.com/sciyoshi/redmine-slack.git redmine_slack

#Redmine Issue Templates Pluginのインストール用モジュールを用意(インストールはredmine起動時に実施)
RUN cd /usr/src/redmine/install_plugins 
 && git clone https://github.com/akiko-pusu/redmine_issue_templates.git redmine_issue_templates

#Redmine Default Custom Query Pluginのインストール用モジュールを用意(インストールはredmine起動時に実施)
RUN cd /usr/src/redmine/install_plugins 
 && git clone https://github.com/hidakatsuya/redmine_default_custom_query.git redmine_default_custom_query

#Redmine Lightbox Plugin 2 Pluginのインストール用モジュールを用意(インストールはredmine起動時に実施)
RUN cd /usr/src/redmine/install_plugins 
 && git clone https://github.com/paginagmbh/redmine_lightbox2.git redmine_lightbox2

#redmine_banner Pluginのインストール用モジュールを用意(インストールはredmine起動時に実施)
RUN cd /usr/src/redmine/install_plugins 
 && git clone https://github.com/akiko-pusu/redmine_banner.git redmine_banner

#redmine_dmsf Pluginのインストール用モジュールを用意(インストールはredmine起動時に実施)
RUN cd /usr/src/redmine/install_plugins 
 && git clone https://github.com/danmunn/redmine_dmsf.git redmine_dmsf

#redmine_omniauth_google Pluginのインストール用モジュールを用意(インストールはredmine起動時に実施)
RUN cd /usr/src/redmine/install_plugins 
 && git clone https://github.com/yamamanx/redmine_omniauth_google.git redmine_omniauth_google

#redmine_omniauth_google Pluginのインストール用モジュールを用意(インストールはredmine起動時に実施)
RUN cd /usr/src/redmine/install_plugins 
 && git clone https://github.com/onozaty/redmine-view-customize.git view_customize

#redmine_local_avatars用モジュールを用意(インストールはredmine起動時に実施)
RUN cd /usr/src/redmine/install_plugins 
 && git clone https://github.com/ncoders/redmine_local_avatars.git

#backlogsのインストール用モジュールを用意(インストールはredmine起動時に実施)
RUN mkdir /usr/src/redmine/install_plugins 
 && cd /usr/src/redmine/install_plugins 
 && git clone https://github.com/AlexDAlexeev/redmine_backlogs.git 
 && cd /usr/src/redmine/install_plugins/redmine_backlogs/ 
 && sed -i -e '11,17d' Gemfile

#database.ymlファイルを置くフォルダを用意
RUN mkdir /config
COPY docker-entrypoint.sh /
RUN chmod +x /docker-entrypoint.sh

ENTRYPOINT ["/docker-entrypoint.sh"]

EXPOSE 3000
CMD ["passenger", "start"]

docker-entrypoint.sh

次にdocker-entrypoint.shファイルです。
githubに公開されているファイル
(https://github.com/docker-library/redmine/blob/41c44367d9c1996a587e2bcc9462e4794f533c15/3.3/docker-entrypoint.sh)
を元にプラグインのインストールを行うコードを記載していきます。

docker-entrypoint.sh
#!/bin/bash
set -e

case "$1" in
    rails|rake|passenger)
        if [ -e '/config/database.yml' ]; then
                    if [ ! -f './config/database.yml' ]; then
                echo "use external database.uml file"
                ln -s /config/database.yml /usr/src/redmine/config/database.yml
            fi
        fi
                if [ -e '/config/configuration.yml' ]; then
                        if [ ! -f './config/configuration.yml' ]; then
                                echo "use external configuration.uml file"
                                ln -s /config/configuration.yml /usr/src/redmine/config/configuration.yml
                        fi
                fi
        if [ ! -f './config/database.yml' ]; then
            if [ "$MYSQL_PORT_3306_TCP" ]; then
                adapter='mysql2'
                host='mysql'
                port="${MYSQL_PORT_3306_TCP_PORT:-3306}"
                username="${MYSQL_ENV_MYSQL_USER:-root}"
                password="${MYSQL_ENV_MYSQL_PASSWORD:-$MYSQL_ENV_MYSQL_ROOT_PASSWORD}"
                database="${MYSQL_ENV_MYSQL_DATABASE:-${MYSQL_ENV_MYSQL_USER:-redmine}}"
                encoding=
            elif [ "$POSTGRES_PORT_5432_TCP" ]; then
                adapter='postgresql'
                host='postgres'
                port="${POSTGRES_PORT_5432_TCP_PORT:-5432}"
                username="${POSTGRES_ENV_POSTGRES_USER:-postgres}"
                password="${POSTGRES_ENV_POSTGRES_PASSWORD}"
                database="${POSTGRES_ENV_POSTGRES_DB:-$username}"
                encoding=utf8
            else
                echo >&2 'warning: missing MYSQL_PORT_3306_TCP or POSTGRES_PORT_5432_TCP environment variables'
                echo >&2 '  Did you forget to --link some_mysql_container:mysql or some-postgres:postgres?'
                echo >&2
                echo >&2 '*** Using sqlite3 as fallback. ***'

                adapter='sqlite3'
                host='localhost'
                username='redmine'
                database='sqlite/redmine.db'
                encoding=utf8

                mkdir -p "$(dirname "$database")"
                chown -R redmine:redmine "$(dirname "$database")"
            fi

            cat > './config/database.yml' <<-YML
                $RAILS_ENV:
                  adapter: $adapter
                  database: $database
                  host: $host
                  username: $username
                  password: "$password"
                  encoding: $encoding
                  port: $port
            YML
        fi

        # ensure the right database adapter is active in the Gemfile.lock
        bundle install --without development test
        if [ ! -s config/secrets.yml ]; then
            if [ "$REDMINE_SECRET_KEY_BASE" ]; then
                cat > 'config/secrets.yml' <<-YML
                    $RAILS_ENV:
                      secret_key_base: "$REDMINE_SECRET_KEY_BASE"
                YML
            elif [ ! -f /usr/src/redmine/config/initializers/secret_token.rb ]; then
                rake generate_secret_token
            fi
        fi
        if [ "$1" != 'rake' -a -z "$REDMINE_NO_DB_MIGRATE" ]; then
            gosu redmine rake db:migrate
        fi

        chown -R redmine:redmine files log public/plugin_assets

        if [ "$1" = 'passenger' ]; then
            # Don't fear the reaper.
            set -- tini -- "$@"
        fi
                if [ -e /usr/src/redmine/install_plugins/redmine_backlogs ]; then
                        mv -f /usr/src/redmine/install_plugins/redmine_backlogs /usr/src/redmine/plugins/
                        bundle update nokogiri
                        bundle install
                        bundle exec rake db:migrate
                        bundle exec rake tmp:cache:clear
                        bundle exec rake tmp:sessions:clear
            set +e
                        bundle exec rake redmine:backlogs:install RAILS_ENV="production"
                        if [ $? -eq 0 ]; then
                echo "installed backlogs"
                                touch /usr/src/redmine/plugins/redmine_backlogs/installed
            else
                echo "can't install backlogs"
                        fi
            set -e
            touch /usr/src/redmine/plugins/redmine_backlogs/installed
        fi
                if [ -e /usr/src/redmine/install_plugins/redmine_local_avatars ]; then
                        mv -f /usr/src/redmine/install_plugins/redmine_local_avatars /usr/src/redmine/plugins/
            bundle install --without development test
            bundle exec rake redmine:plugins:migrate RAILS_ENV=production
                fi
        if [ -e /usr/src/redmine/install_plugins/redmine_slack ]; then
            mv -f /usr/src/redmine/install_plugins/redmine_slack /usr/src/redmine/plugins/
            bundle install --without development test
            bundle exec rake redmine:plugins:migrate RAILS_ENV=production
        fi
        if [ -e /usr/src/redmine/install_plugins/redmine_issue_templates ]; then
            mv -f /usr/src/redmine/install_plugins/redmine_issue_templates /usr/src/redmine/plugins/
            bundle install --without development test
            bundle exec rake redmine:plugins:migrate RAILS_ENV=production
        fi
        if [ -e /usr/src/redmine/install_plugins/redmine_default_custom_query ]; then
            mv -f /usr/src/redmine/install_plugins/redmine_default_custom_query /usr/src/redmine/plugins/
            bundle install --without development test
            bundle exec rake redmine:plugins:migrate RAILS_ENV=production
        fi
        if [ -e /usr/src/redmine/install_plugins/redmine_lightbox2 ]; then
            mv -f /usr/src/redmine/install_plugins/redmine_lightbox2 /usr/src/redmine/plugins/
            bundle install --without development test
            bundle exec rake redmine:plugins:migrate RAILS_ENV=production
        fi
        if [ -e /usr/src/redmine/install_plugins/redmine_banner ]; then
            mv -f /usr/src/redmine/install_plugins/redmine_banner /usr/src/redmine/plugins/
            bundle install --without development test
            bundle exec rake redmine:plugins:migrate RAILS_ENV=production
        fi
        if [ -e /usr/src/redmine/install_plugins/redmine_dmsf ]; then
            mv -f /usr/src/redmine/install_plugins/redmine_dmsf /usr/src/redmine/plugins/
            bundle install --without development test xapian
            bundle exec rake redmine:plugins:migrate RAILS_ENV=production
        fi
        if [ -e /usr/src/redmine/install_plugins/redmine_omniauth_google ]; then
            mv -f /usr/src/redmine/install_plugins/redmine_omniauth_google /usr/src/redmine/plugins/
            bundle install --without development test
            bundle exec rake redmine:plugins:migrate RAILS_ENV=production
        fi
        if [ -e /usr/src/redmine/install_plugins/view_customize ]; then
            mv -f /usr/src/redmine/install_plugins/view_customize /usr/src/redmine/plugins/
            bundle install --without development test
            bundle exec rake redmine:plugins:migrate RAILS_ENV=production
        fi
        if [ ! -f '/usr/src/redmine/plugins/redmine_backlogs/installed' ]; then
            set +e
            bundle exec rake redmine:backlogs:install RAILS_ENV="production"
            if [ $? -eq 0 ]; then
                echo "installed backlogs"
                touch /usr/src/redmine/plugins/redmine_backlogs/installed
            else
                echo "can't install backlogs"
            fi
            set -e
        fi
        set -- gosu redmine "$@"
                ;;
esac

exec "$@"

次はこのイメージをAWSのECSにて動作させます。
(次回に続く)

続きを読む

〇FLAGの中の人に憧れてMastodon×AWSでモンストドン作ってみた

Mastodon立ち上げたらいい会社に入れると聞いて、邪な気持ちで。。。いや、Mastodonとモンストって相性よさそうだなぁと思いたち、少し乗り遅れた感をかもしだしながら、フルにAWSを使って規模拡大しても大丈夫な構成で作ってみた。

モンストドン (https://monstdn.com)

構成

monstdn.png

最小構成のざっくり料金($1=113円、1ヶ月30日計算)

サービス 単価 月額料金
ALB 1台 × $0.0243/1H + データ転送的なの  約2000円 + α
EC2 2台(t2.nano) × $0.008/1H + データ転送的なの 約1300円 + α
RDS 1台(db.t2.micro シングルAZ) $0.028/1H + データ転送的なの 約2300円 + α
ElasticCache 1台(cache.t2.micro) $0.026/1H + データ転送的なの 約2100円 + α
S3Bucket $0.025/GB + リクエスト数的なの + α
SES $0.10/1,000通あたり + データ転送的なの + α
合計     ( 約7700円 + α なので ) ざっくり1万ぐらい

※無料枠があるので1年目はもう少しやすくできそう

やったこと

  • AWSのアカウント作成
  • IAMの作成とアカウントの初期設定(二段階認証とか、パスワードポリシーとか)
  • Route53でドメインを買う
  • SESでメール設定と制限解除申請
  • ACMの取得(無料でHTTPS通信)
  • S3バケット作成(画像とかのアップロードファイルの配信用)
  • VPCとセキュリティグループの作成
  • SES、S3へアクセスする為のIAMユーザの作成
  • ElasticCacheでRedisの作成
  • RDSでPostgreSQLの作成
  • EC2でCentOSを使ってMastodonの構築(下に詳細)とイメージ(AMI)の作成
  • AutoScallingの設定
  • ALB(ApplicationLoadBalancer)の作成(ACMをつける)
  • Route53でHostZoneのレコード設定

CentOSでのMastdon構築(20170517現在)

sudo su -
yum -y update
yum -y install vim

localectl set-locale LANG=ja_JP.utf8
localectl set-keymap jp106
localectl status

timedatectl set-timezone Asia/Tokyo
timedatectl status

dd if=/dev/zero of=/mnt/swapfile bs=1M count=2560
mkswap /mnt/swapfile
swapon /mnt/swapfile
chmod 0644 /mnt/swapfile
echo "/mnt/swapfile                             swap                    swap    defaults                0 0" >> /etc/fstab
free

vim /etc/sysconfig/selinux
 SELINUX=enforcing
 ↓
 SELINUX=disabled

systemctl disable postfix
systemctl disable auditd.service

yum -y install libxml2-devel ImageMagick libxslt-devel git curl nodejs file
yum -y install epel-release
rpm --import http://li.nux.ro/download/nux/RPM-GPG-KEY-nux.ro
rpm -Uvh http://li.nux.ro/download/nux/dextop/el7/x86_64/nux-dextop-release-0-5.el7.nux.noarch.rpm
yum -y install ffmpeg ffmpeg-devel

yum -y group install "Development tools"
curl -sL https://rpm.nodesource.com/setup_4.x | sudo bash -

yum -y install nodejs
npm -g install yarn

yum -y install postgresql postgresql-contrib postgresql-devel
yum install -y openssl-devel readline-devel

useradd mastodon
passwd mastodon
su - mastodon
git clone https://github.com/rbenv/rbenv.git ~/.rbenv
cd ~/.rbenv && src/configure && make -C src && cd ~
echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bash_profile
echo 'eval "$(rbenv init -)"' >> ~/.bash_profile && source ~/.bash_profile
git clone https://github.com/rbenv/ruby-build.git ~/.rbenv/plugins/ruby-build
rbenv install 2.4.1 && rbenv global $_ && rbenv rehash

# 確認
ruby -v

cd ~
git clone https://github.com/tootsuite/mastodon.git live
cd live
git checkout $(git tag | tail -n 1)

gem install bundler
bundle install --deployment --without development test
yarn install --pure-lockfile

cp .env.production.sample .env.production
sed -i "/^PAPERCLIP_SECRET=$/ s/$/`rake secret`/" .env.production
sed -i "/^SECRET_KEY_BASE=$/ s/$/`rake secret`/" .env.production
sed -i "/^OTP_SECRET=$/ s/$/`rake secret`/" .env.production

vim .env.production
#Redis,Postgresql,言語,SMTP,S3の設定

RAILS_ENV=production bundle exec rails db:setup
RAILS_ENV=production bundle exec rails assets:precompile

exit

cat << "_EOF_" > /etc/systemd/system/mastodon-web.service
[Unit]
Description=mastodon-web
After=network.target

[Service]
Type=simple
User=mastodon
WorkingDirectory=/home/mastodon/live
Environment="RAILS_ENV=production"
Environment="PORT=3000"
ExecStart=/home/mastodon/.rbenv/shims/bundle exec puma -C config/puma.rb
TimeoutSec=15
Restart=always

[Install]
WantedBy=multi-user.target
_EOF_


cat << "_EOF_" > /etc/systemd/system/mastodon-sidekiq.service
[Unit]
Description=mastodon-sidekiq
After=network.target

[Service]
Type=simple
User=mastodon
WorkingDirectory=/home/mastodon/live
Environment="RAILS_ENV=production"
Environment="DB_POOL=5"
ExecStart=/home/mastodon/.rbenv/shims/bundle exec sidekiq -c 5 -q default -q mailers -q pull -q push
TimeoutSec=15
Restart=always

[Install]
WantedBy=multi-user.target
_EOF_

cat << "_EOF_" > /etc/systemd/system/mastodon-streaming.service
[Unit]
Description=mastodon-streaming
After=network.target

[Service]
Type=simple
User=mastodon
WorkingDirectory=/home/mastodon/live
Environment="NODE_ENV=production"
Environment="PORT=4000"
ExecStart=/usr/bin/npm run start
TimeoutSec=15
Restart=always

[Install]
WantedBy=multi-user.target
_EOF_

systemctl enable mastodon-{web,sidekiq,streaming}
systemctl start mastodon-{web,sidekiq,streaming}

cat << "_EOF_" | crontab -
RAILS_ENV=production
@daily cd /home/mastodon/live && /home/mastodon/.rbenv/shims/bundle exec rake mastodon:daily > /dev/null
_EOF_

yum -y install nginx

cat << "_EOF_" > /etc/nginx/conf.d/mastodon.conf
map $http_upgrade $connection_upgrade {
  default upgrade;
  ''      close;
}

server {
  listen 80;
  listen [::]:80;
  server_name {domainName};

  keepalive_timeout    70;
  sendfile             on;
  client_max_body_size 0;

  root /home/mastodon/live/public;

  gzip on;
  gzip_disable "msie6";
  gzip_vary on;
  gzip_proxied any;
  gzip_comp_level 6;
  gzip_buffers 16 8k;
  gzip_http_version 1.1;
  gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;

  add_header Strict-Transport-Security "max-age=31536000";

  location / {
    try_files $uri @proxy;
  }

  location @proxy {
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto https;
    proxy_set_header Proxy "";
    proxy_pass_header Server;

    proxy_pass http://127.0.0.1:3000;
    proxy_buffering off;
    proxy_redirect off;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection $connection_upgrade;

    tcp_nodelay on;
  }

  location /api/v1/streaming {
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto https;
    proxy_set_header Proxy "";

    proxy_pass http://localhost:4000;
    proxy_buffering off;
    proxy_redirect off;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection $connection_upgrade;

    tcp_nodelay on;
  }

  error_page 500 501 502 503 504 /500.html;
}
_EOF_

systemctl enable nginx
systemctl start nginx

# ユーザ登録後 admin設定
RAILS_ENV=production bundle exec rails mastodon:make_admin USERNAME={UserName}

メモ

EC2のDiskはSSDで(swapで使う)
ロードバランサーはApplicationの方じゃないとwebSocketがうまくいかない
コミュニティベースのシステムだからCloudFrontはあまり必要性感じなかったので使わなかった
(日本向けだしS3のバケット東京リージョンにあるし、S3もかなり性能いいし)
もしCloudFrontを使うなら、websocketできないからS3の前に置く感じ
今回CloudFrontの利点があるとすれば”ドメイン”が自分の使えることぐらいかな
CentOSじゃなくてAmazonLinux使いたかったけど、ffmpeg入れるのにやたら時間かかったからやめた。一応動いたけど(純正AWSが。。。)
DockerはDeployまで楽そうだけど、効率よくなさそうだったのでやめた
AWSでDocker使うならECSでやってみたいけど、Mastodonはすんなりできるのかなー
セキュリティ的にはロードバランサーからの80番ポートしか受け付けないように制御してるから大丈夫かな。
sshでのログインは同じVPC内に踏み台サーバ立ててと。

最後に

ここまで読んで頂きありがとうございます。
技術的なことを投稿するのはこれが初めてですが、だれかのお役にたてれたら嬉しいです。
普段はPHPとAWS少しいじる程度なのでいい勉強になりました。
ほとんど公開されている文献をもとにプラモデル感覚で作りましたので、ご指摘等あればコメント頂ければと思います。
個人でのサイト運用となりますので、落ちたらごめんなさい。

続きを読む

IAM認証RDS�・非VPC Lambda・API Gateway・CloudFront・WAFで接続元IP制限付きAPIを作成する

主に以下2例に対して情報を少し追加するだけの記事です。

API GatewayのバックをVPC Lambdaにしている場合、APIのくせに返答に時間がかかる場合がある、という問題があります。なので、

  • 非VPC Lambdaから安全にPublic AccessibleなRDSに接続したい
  • かつ、API Gatewayに接続元IP制限をつけたい

というのがやりたいことです。

RDS接続認証でIAMが使えるようになった

執筆時点で公式日本語ドキュメントは無し。

つまりどういうこと?

MySQLの認証プラグインを作ったからRDSイメージにいれておいたよー、という話らしいので見てみる。

select * from plugin;
+-------------------------+-------------+
| name                    | dl          |
+-------------------------+-------------+
| AWSAuthenticationPlugin | aws_auth.so |
+-------------------------+-------------+
1 row in set (0.01 sec)

同じものをPostgreSQLでも作ってくれればPostgreSQLでもIAM認証が使える用になるんですよね? (よく知らないまま希望)

それのなにがうれしいの?

MySQLのuser/password認証がAWS_ACCESS_KEY_IDとAWS_ACCESS_SECRET_KEYに置き換わったような感じです。

……って言っちゃうと「それはそう」案件になるんですが、特定のIAMロールを持つ非VPC Lambdaからのみのアクセスを許可するようなRDS MySQLを作ることができる、というのが特にうれしい点です。

MySQL組み込みの認証機構よりは比較的安全な方法で、RDSをPublic Accessibleにできるようになる、とも言います。RDSがPublic Accessibleなら、Lambdaも非VPCでよくなります。しかもそのLambdaも特定のIAMロールを持つものだけに制限できます。安心だ。

やりたいこと

RDS (IAM & SSL) | AWS Lambda (IAM) | API Gateway (https) | CloudFront (https) | Web Application Firewall

rds-iam.png

の構成を作りたい。社内APIとかですな。なんか登場人物が多いですが、以下の事情があります

  • ソースIP制限をつけたいが、API Gateway自体にソースIP制限機能がない
  • WAFにはあるが、WAFはALBかCloudFrontにしか使えない

よって、

  • CloudFrontをAPI Gatewayの前段に置く
  • WAFをCloudFrontの前段に置く

ことでアクセスをコントロールします。

API Gateway自体に関しては、API Tokenを必須にすることでアクセスを制限します。もちろんCloudFrontからはアクセスできないといけないので、Origin設定でAPI Tokenをヘッダに追加する必要があります。ややこしいなおい。

ちなみに、API Gatewayの認証をIAMにすることもできるんですが、これだとAPIユーザーにAWS v4 Signature Authを実装させることになるので心苦しいです。

うっわめんどくさっ。

やってみよう

RDSをつくる

IAM Database Authentication for MySQL and Amazon Aurora

IAM認証はdb.m1.smallより大きいインスタンスのみでしか使えないので注意。ユーザーの作り方もドキュメントのままですが、

CREATE USER jane_doe IDENTIFIED WITH AWSAuthenticationPlugin as 'RDS' REQUIRE SSL;

DBとLambda間はSSLにしないといけないので、REQUIRE SSLオプションを付けてSSLを強制します。

Lambdaのレンジ:3306のInをAllowしたSecGroupを作る、つってもLambdaのレンジってめっちゃ広そう?
https://docs.aws.amazon.com/ja_jp/general/latest/gr/aws-ip-ranges.html

Lambdaをつくる

試しに作ったLambdaは

from __future__ import print_function

import os

import boto3
import mysql.connector

def lambda_handler(event, context):
    print(event, context)
    token = boto3.client('rds').generate_db_auth_token(
        DBHostname=os.environ['RDS_HOST'],
        Port=3306,
        DBUsername=os.environ['RDS_USER']
    )
    conn = mysql.connector.connect(
        host=os.environ['RDS_HOST'],
        user=os.environ['RDS_USER'],
        password=token,
        database=os.environ['RDS_DATABASE'],
        ssl_verify_cert=True,
        ssl_ca='rds-combined-ca-bundle.pem'
    )
    cursor = conn.cursor()
    cursor.execute('SELECT user FROM mysql.user')
    rows = cursor.fetchall()
    result = [str(x[0]) for x in rows]
    return {'users': result}

DBのユーザーをSELECTして返すだけのものです。

Lambda実行時のIAMロールにIAM Database Authポリシーが必要になります。

Attaching an IAM Policy Account to an IAM User or Role

arn:aws:rds-db:region:account-id:dbuser:dbi-resource-id/database-user-name

ここでMySQLのGRANTONTOを指定しているみたいなものと考える。

別のIAMロールを付けてLambdaを実行してみると、みごとにDB接続エラーが発生する。

Lambdaをzipでまとめる

Dockerfileを作ってzipを生成するナウでヤングな最先端のイカしたアレだぜ。デプロイ時に非VPCを選択。

FROM amazonlinux

RUN yum install -y python27-devel python27-pip zip
RUN pip install --upgrade pip
RUN mkdir /opt/rds-iam-auth /opt/build
COPY ./ /opt/rds-iam-auth/
WORKDIR /opt/rds-iam-auth
RUN pip install wheel
RUN pip install -r requirements.txt -t .
RUN zip -r rds-iam-auth.zip *

CMD cp rds-iam-auth.zip /opt/build

悲しいかなLambdaのamazonlinuxに入っているboto3がIAM RDS authに未対応 (執筆時) だったのでrequirement.txtに追記。近々AMIもアップデートされるだろう。

その他をつくる

コンソールからぽちぽちやる作業がたくさんあります。特にここで追記することはないので、先人の記事を参照したいところだ。

注意点まとめ

  • APIエンドポイントを直接使用されないように、API Tokenを必須にしておくこと。
  • WAFはGlobalリージョンで作成しないとCloudFrontのコンソールから選べないので注意。
  • CloudFrontのOrigin設定時に、x-api-tokenヘッダ転送設定を追加すること。
  • CloudFrontの設定反映には時間がかかるの辛いコーヒー飲むしかない。

ためす

WAFで社内のGlobal IPのみアクセスを許可。

$ curl https://hoge.cloudfront.net/
{"users": ["helloworld", "iamuser1", "mysql.sys", "rdsadmin"]}

WiFi変えたりとかして、Global IPを変えてみると

$ curl https://hoge.cloudfront.net/
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<HTML><HEAD><META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
<TITLE>ERROR: The request could not be satisfied</TITLE>
</HEAD><BODY>
<H1>ERROR</H1>
<H2>The request could not be satisfied.</H2>
<HR noshade size="1px">
Request blocked.
<BR clear="all">
<HR noshade size="1px">
<PRE>
Generated by cloudfront (CloudFront)
Request ID: jIG5TSJUn9rPZYI0JwUr9wZHFHFa_LRyVmwGC302sHjBgv0sLoPubA==
</PRE>
<ADDRESS>
</ADDRESS>
</BODY></HTML>

Forbiddenされる。

まとめ

AWSよくできてんなー。

続きを読む

AWSでMastodonインスタンスを作るまで。自分まとめ

だいたいネットのチュートリアル通り

http://webfood.info/mastodon-aws-tutorial/
だいたいこの通りにやると構築できます(終了)

とするのも寂しいので、自分の環境で再現できるように、手順と詰まりやすい所を残しておきますね。

1.VPCを作る Virtual Private Cloud

A. まず、AWSから借りるサーバーをひとまとめにする仮想イントラネット、VPCを作ります。

image.png

この時、CIDR ブロックは XX.0.0.0/16をお勧めします。
ウィザード通りで大丈夫かと
image.png

↓ここからはVPCでトラブった時の雑学 CIDR ブロックについて若干おさらい。

VPCってなんだっけ。情報の授業のおさらい

VPCはAWSの仮想イントラネットです。VPCはサブネットマスクを使って自身のネットワーク内に
あるサーバーや更なるサブネットのアドレスを割り当てます。

こんな感じ、0が自分のネットワーク内で使えるアドレス

XX.0.0.0.0/24のサブネットマスク
11111111.11111111.11111111.00000000
0の数が8つ
2^8 = 256 のIPを割り振る事ができる。

XX.0.0.0.0/16のサブネットマスク
11111111.11111111.00000000.00000000
0の数が8つ
2^16 = 65536 のIPを割り振る事ができる。
これが分かってないと時々サブネットが作れず詰みになったりします。

情報の授業終わり

パブリックサブネットを作る

外部からSSH接続できるように仮想ルーターを配置します。
VPCの作成ウィザードで作成されてると思いますが、作られてなかったら、

A’ VPCダッシュボードからインターネットゲートウェイインターネットゲートウェイの作成で仮想ルーターを作ります。

仮想ルーターが出来たら、VPCにアタッチで作成したVPCとルーターを繋ぎます。
これで仮想ネットワークがインターネットに接続されました。

ですが、まだルーターがあるだけです。どのサブネットを作り、ルーターと接続します。
B’ サブネットの作成をクリックして先ほど作ったVPCにサブネットを作ります。
サブネットに割り当てるCIDRはXX.0.0.0.0/24がおすすめ

そして作成したサブネットをチェックし、ルートテーブルタブをクリック。
現在のルートテーブルを編集し、サブネットとインターネットゲートウェイをつなぎます。
image.png

rtb-XXXXXXXをクリックして編集します。

image.png

ルートタブから別ルートの追加 送信先を0.0.0.0/0 ターゲットをigw-XXXXXX(先ほど作成したインターネットゲートウェイのID)
を指定します。
これで、このサブネットにある仮想コンピューターはすべてインターネットからアクセスできるようになりました。
↑ここまで、VPCでトラブるケース。

2.インスタンスを作る。

A. Mastodonを実行するインスタンスを作ります。
インスタンスの作成をクリック
image.png

GithubのREADMEがUbuntuを推奨しているのでOSはUbuntuを選択するのがいいと思います。
一応はAmazon Linuxでも動く模様。
インスタンス詳細は先ほど作成したVPCサブネットを選択

image.png

ストレージは8Gだとすぐいっぱいになるっぽい。
20GBだとそれなりー、との噂を聞いたかも(曖昧)

セキュリティグループの設定

B. SSH接続からインスタンスを操作するようにセキュリティグループを作ります。

image.png

マイIPを選択し、自分のコンピューターからSSHポートが繋がるようにします。

image.png

画面には移りませんがSSH接続するのに、RSA暗号を使います。
インスタンスを作成時にキーペアが作成されるので自分用の秘密鍵を大切に保管してください。(秘密鍵が漏れて、自分の仮想コンピューターで好き勝手されて、20万の請求が来たとかいう話も)
これを失くすとインスタンスに接続できません。必ず漏れないように大切に保管してください。

C. 外部から接続できるようにインスタンスにパブリックIPを設定します。
サービス > EC2インスタンス > Elastic IP
から新しいアドレスの割り当てでパブリックIPを取得します。
パブリックIPが取得出来たらアクション > IP の関連付けで先ほど作成したインスタンスにIPを割り当てます。

3インスタンスに接続する。

A. まず、自分はwindowsなのでSSHクライアントをダウンロードします。
Putty」でググってダウンロード
image.png

B. インストーラーをダウンロードしてウィザードに従ってインストールします。

C. Puttyをインストールしたら、ダウンロードした秘密鍵をPutty形式に変換します。
PuTTYgenを起動してLoadをクリック

先ほど保存した秘密鍵ファイルを選びます。

image.png

選択したらsave private keyを選択し、秘密鍵を保存します。

A. いよいよインスタンスに接続します。
Puttyを起動します。
左のタブから SSH > Auth からBrowseボタンを押して、先ほど保存した秘密鍵を選択
image.png

秘密鍵を読み込んだら、
sessionを選択
Host Nameubuntu@XX.XX.XX(インスタンスに割り当てたパブリックIP)を入力
ここまで言ったら接続設定を保存しましょう
Saved Sessions適当な名前を入れて接続設定を保存します。

image.png

接続設定を保存したら、Openをクリック

image.png

こういう系の画面が出たら成功です。
これでLinuxサーバーが操作が操作できます。

4.マストドンのセットアップ

ここからは完全に上述のテキスト通りです。

まず、メモリが足りないっぽいので、スワップファイルを作ります。

先ほどのコンソールにコマンドを打ち込みます。

$ sudo fallocate -l 4G /swapfile
$ sudo chmod 600 /swapfile
$ sudo mkswap /swapfile
$ sudo swapon /swapfile
$ echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab

パッケージを最新にします。

$ sudo apt-get update
$ sudo apt-get upgrade

途中grub関連(?)の更新が聞かれますが

keep the local version currently installed

を選択してください。(どっちでも大丈夫だとは思うけど念のため)

マストドンのビルドetcに必要なソフトを入れます

$ sudo apt-get install -y python3-pip unzip docker.io nginx
$ sudo pip3 install docker-compose

上のテキスト通り、nginxの設定ファイルを編集します。

$ sudo vim /etc/nginx/sites-enabled/default

元々機能してた部分は#でコメントアウトします。
XX.XX.XX.XXの部分はインスタンスのパブリックIP

置き換える内容は以下の通りで。

map $http_upgrade $connection_upgrade {
  default upgrade;
  ''      close;
}

#server {
#  listen 80;
#  listen [::]:80;
#  server_name XX.XX.XX.XX;
#  return 301 https://$host$request_uri;
#}

server {
  listen 80;
  listen [::]:80;
  server_name XX.XX.XX.XX;
  #listen 443 ssl;
  #listen [::]:443 ssl;
  #server_name XX.XX.XX.XX;

  #ssl_protocols TLSv1.2;
  #ssl_ciphers EECDH+AESGCM:EECDH+AES;
  #ssl_ecdh_curve prime256v1;
  #ssl_prefer_server_ciphers on;
  #ssl_session_cache shared:SSL:10m;

  #ssl_certificate     /etc/letsencrypt/live/everydon.com/fullchain.pem;
  #ssl_certificate_key /etc/letsencrypt/live/everydon.com/privkey.pem;

  keepalive_timeout    70;
  sendfile             on;
  client_max_body_size 0;

  #root /home/mastodon/live/public;
  gzip on;
  gzip_disable "msie6";
  gzip_vary on;
  gzip_proxied any;
  gzip_comp_level 6;
  gzip_buffers 16 8k;
  gzip_http_version 1.1;
  gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;

  add_header Strict-Transport-Security "max-age=31536000";

  location / {
    try_files $uri @proxy;
  }

  location @proxy {
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    #proxy_set_header X-Forwarded-Proto https;
    proxy_set_header Proxy "";
    proxy_pass_header Server;

    proxy_pass http://127.0.0.1:3000;
    proxy_buffering off;
    proxy_redirect off;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection $connection_upgrade;

    tcp_nodelay on;
  }

  location /api/v1/streaming {
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    #proxy_set_header X-Forwarded-Proto https;
    proxy_set_header Proxy "";

    proxy_pass http://localhost:4000;
    proxy_buffering off;
    proxy_redirect off;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection $connection_upgrade;

    tcp_nodelay on;
  }

  error_page 500 501 502 503 504 /500.html;
}

こんな感じになってるはず。
image.png

Nginxを再起動します。

$ sudo systemctl start nginx

これで、インスタンスのセキュリティグループをHTTPを任意のIPにすることでサーバーに接続できるはずです

Githubからマストドンのソースを持ってきます。

$ git clone https://github.com/tootsuite/mastodon

念のため、最新版を確認

$ cd mastodon
$ git tag -l
$ git checkout -b x.x.x refs/tags/vx.x.x(x.x.xは最新版のバージョン)

これでマストドンのソースがダウンロードされるはずです。

設定ファイルをコピーします。

$ cp .env.production.sample .env.production

設定ファイルの中でDBの永続化設定をします。

env.production
db:
  restart: always
  image: postgres:alpine
## Uncomment to enable DB persistance
  volumes:
    - ./postgres:/var/lib/postgresql/data

redis:
  restart: always
  image: redis:alpine
## Uncomment to enable REDIS persistance
  volumes:
    - ./redis:/data

dbとradisにある

  volumes:
    - ./nanntoka

の部分のコメントアウト(#)を外します

いよいよマストドンのビルドです
下記のコマンドを実行

$ sudo docker-compose build

5.マストドンの設定

マストドンが使うカギを生成します。
下記のコマンドを3回実行し、文字列をそれぞれどこかにコピーします。

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

こういう感じの文字列が出力されます。
3回コピーしてください。

4b804c1e71d14951a50cbc52f3b8a7ef9d1bf993e2774227cdf637102022f4a5af188aa4fa4c236b31e4ed6970469d1527e06097b678edfb0ed9e6d85c18d805

設定ファイルをもう一回いじります。

$ vim .env.production

ドメインの設定、後でもう一度設定し直します。

# Federation
LOCAL_DOMAIN=XX.XX.XX.XX
LOCAL_HTTPS=false

秘密鍵を入力します
=の先に3つの秘密鍵を入力

# Application secrets
# Generate each with the `rake secret` task (`docker-compose run --rm web rake secret` if you use docker compose)
PAPERCLIP_SECRET=
SECRET_KEY_BASE=
OTP_SECRET=

日本語設定はパス

DBのマイグレーションをします。
マストドンが使うデータベースの初期設定ですね。

$ sudo docker-compose run --rm web rails db:migrate

マストドンが使う固定ファイルを生成します。

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

ここで、Nginxを再起動します。
マストドンはport3000とport4000で動きますが、
以降は80ポートに来たアクセスをNginxがport3000とport4000に割り振ります。

マストドンへのアクセスの玄関口になる訳ですね。

$ sudo systemctl stop nginx
$ sudo systemctl start nginx

マストドンを起動します

$ sudo docker-compose up -d

マストドンが起動しました。

http://XX.XX.XX.XX/

にアクセスするとマストドンのトップページに飛ぶはずです。

mastodon-top.png

6.連携ソフトの設定

マストドンが利用するメールサービスを設定します。
メールはAWSのメールサービスSESを利用します。

ただ、途中です

続きを読む

AWSでマストドンインスタンスを立てる

マストドンインスタンスを立てた。

筋トレやダイエットに関するコミュニティになれば良いと思って筋肉インスタンスを立てました。
Muscledon

AWSでマストドンを立てる

という記事を書こうかと思ったが既に完璧な手順があった。同じ内容の記事はフヨウラ!

マストドンAWS構築チュートリアル完全版|初心者から大規模運用まで

とはいえこの記事通りに進めているうちにつまったところがあるので解決法を提示する。

docker-compose buildに失敗する。

apt-getでdockerを入れるとバージョンが古く、buildに失敗してしまう。
新しいバージョンのdocker及びdocker-composeの入れ方は以下の兄貴の記事を参考にしてほしい。
DockerとDocker Composeをインストール

docker-compose buildに失敗する。

上記の対応を行っても以下のようなエラーで失敗してしまった。

ERROR: https://nl.alpinelinux.org/alpine/edge/main: operation timed out
WARNING: Ignoring APKINDEX.65bdaf85.tar.gz: No such file or directory
OK: 21 MiB in 29 packages
WARNING: Ignoring APKINDEX.65bdaf85.tar.gz: No such file or directory
WARNING: The repository tag for world dependency 'nodejs@edge' does not exist
WARNING: The repository tag for world dependency 'nodejs-npm@edge' does not exist
WARNING: The repository tag for world dependency 'imagemagick@edge' does not exist
ERROR: Not committing changes due to missing repository tags. Use --force to override.
ERROR: Service 'streaming' failed to build: The command '/bin/sh -c echo "@edge https://nl.alpinelinux.org/alpine/edge/main" >> /etc/apk/repositories  && BUILD_DEPS="     postgresql-dev     libxml2-dev     libxslt-dev     python     build-base"  && apk -U upgrade && apk add     $BUILD_DEPS     nodejs@edge     nodejs-npm@edge     git     libpq     libxml2     libxslt     ffmpeg     file     imagemagick@edge     ca-certificates  && npm install -g npm@3 && npm install -g yarn  && update-ca-certificates  && rm -rf /tmp/* /var/cache/apk/*' returned a non-zero code: 255

原因としては*.alpinelinux.orgのサーバがダウンしているためだ。
この記事を書いている現在2017/05/05 20:00もアクセス出来ない状態になっている。
2017/05/05 22:40現在復活している。
https://alpinelinux.org/

リポジトリの向き先をalpineのCDNに変更してやるとよい。
cloneしてきたmastodonディレクトリ直下にあるDockerfileを編集する。

Dockerfile
- RUN echo "@edge https://nl.alpinelinux.org/alpine/edge/main" >> /etc/apk/repositories \
+ RUN echo "@edge http://alpine.gliderlabs.com/alpine/edge/main" >> /etc/apk/repositories \

ユーザー数が0人と表示される。

何故か「このインスタンスについて」のユーザー数が0人と表示されていた。
原因はMastodonアプリとDBのタイムゾーンが異なっているためだった。
DBは日本時間だったがEC2インスタンスはUTCだったので日本時間に合わせる。

mastodon/config/application.rb
-    # config.time_zone = 'Central Time (US & Canada)'
+    config.time_zone = 'Tokyo'

HTTP/2に対応させる。

nginxでもいじってHTTP/2に対応させてやるか!
と思っていたら既にHTTP/2になっていた。どうやらAWSのロードバランサでapplicationを選択するとHTTP/2になるようだ。

サイトの管理画面を出す。

ここに書いてある通りなのだが、
まずユーザーを作って(ここではaliceというユーザとしよう)メール認証を済ませる。
そして以下のコマンドを打ち込むのだが

RAILS_ENV=production bundle exec rails mastodon:make_admin USERNAME=alice

では上手くいかなかった。
かわりに

sudo docker-compose run --rm web rails mastodon:make_admin USERNAME=alice

ならうまくいった。:relaxed:

mastodonのdaily taskを追加する。

こちらの兄貴が書いている通りmastodon:dailyを実行してやらないと
国交を断絶されてしまうらしい。cronにタスクを追加してカイコクシテクダサーイ

Postgres Redis ストレージを切り離す。

投稿画像、動画をS3に保存するように変更する。

こちらの兄貴のやり方に従って作業すれば良い。
ただしS3を使っているのであれば以下の設定は不要(検証済み)
S3の代わりに別のサーバを使う場合は必要らしい。

.env.production
# S3_PROTOCOL=
# S3_ENDPOINT=

mastodonは変化し続ける可能性の獣

mastodonのGithubを見ると最終コミットが数時間前だったりする。
頻繁に変化し続けているのでちょいちょいバグる。二回ほど構築してみたが、一回目は管理画面からサイトの編集が出来なかったが、二回目は出来るようになった。
今のところCloneするタイミングによってかなり挙動が変わるようだ。

とかUCな気持ちに浸っていたら公式にはこう書いていた。

Please note: It is highly recommended to run a tagged release of Mastodon and not run off the current master branch.

訳:間違ってもMasterのブランチからクローンなんかすんじゃねーぞ。

続きを読む