JAWS DAYS 2017 ワークショップ Docker on Elastic Beanstalk 〜Days after tomorrow〜 (2)

この記事では、複数のDockerコンテナで構成される環境を構築するための設定例を具体的に解説します。ワークショップのフォローアップではありますが、一般的な事柄を扱いますので、ワークショップに参加されていない方にもお読み頂ける内容です。

前回の記事: JAWS DAYS 2017 ワークショップ Docker on Elastic Beanstalk 〜Days after tomorrow〜 (1)

春ですね

こんにちは。Emotion Techの子安です。ようやく暖かくなってきましたね。やっぱり春といえば桜ですかね!

sakura.jpg

恐縮です。

前回のつづき

さて、前回はテーマとする環境の構成を説明し、利用するコンテナ定義ファイル docker-compose.yml の枠組みを解説しました。更に web app db コンテナのうち、 web db コンテナの設定を見ました。今回はアプリケーションそのものである app コンテナを見ていきます。

各コンテナの設定 2

appコンテナ

app:
  image: phusion/passenger-ruby23:0.9.20
  environment:
    APPLICATION_ENV: development
    APPLICATION_ROLE: app
    PASSENGER_APP_ENV: development
  labels:
    eb.workshop.role: app
  networks:
    - eb.workshop
  depends_on:
    - db
  volumes:
    - ./app/init/40_setup.sh:/etc/my_init.d/40_setup.sh:ro
    - ./app/passenger/passenger.conf:/etc/nginx/sites-available/default:ro
    - ./app/rails-app:/var/www/rails-app

Ruby on Railsのアプリを実行するappコンテナです。phusion/passenger-dockerイメージを利用しています。このイメージはさまざまな機能を持っていますが、まずは設定内容を見ましょう。

  • image: phusion/passenger-dockerイメージを指定しています。
  • environment: イメージ側で PASSENGER_APP_ENV 環境変数を読んでRailsの環境を切り替えてくれる機能があります。
  • volumes: ここで3つのマウントを指定しています。コンテナ側のパスを見てください。

    • /etc/my_init.d/40_setup.sh:ro: /etc/my_init.d 配下に置いたスクリプトを初期化時に実行してくれる機能があります。実行権限を忘れずにつけるようにします。 :ro は読み取り専用の意味です。
    • /etc/nginx/sites-available/default:ro: ここにnginxの設定ファイルが置かれています。
    • /var/www/rails-app: Railsのアプリケーションをここに置きます。これは任意の場所で構いません。上記のnginx設定ファイルに記述しています。

phusion/passenger-docker

phusion/passenger-dockerは、Phusion社がメンテナンスしているDockerイメージです。このイメージは、さらに別のイメージ phusion/baseimage-docker をベースとして作られています。このphusion/baseimage-dockerには、いくつかの有用な機能が含まれています。

  • 正しいinitプロセス: /sbin/my_init にinitプロセスを内蔵しています。本来initプロセスには、親プロセスのいなくなった子プロセス(孤児)を里親として引き受ける役割があります。加えて SIGTERM を受け取った際に、他のサービスを終了させる機能を持ちます。
  • スーパーバイザ: 軽量なスーパーバイザ runit を内蔵しています。
  • ログマネージャ: syslogデーモン syslog-ng を内蔵しています。logrotateも設定済みです。
  • cron: cronデーモンを内蔵しています。

重要なことは、これらの機能が協調動作するように設定されていることです。 /sbin/my_init がrunitを立ち上げ、runitがsyslog-ngやcronを管理します。デフォルトのコンテナ起動コマンドが /sbin/my_init に設定されていますので、

docker run phusion/baseimage

として起動することで、最小限のコンテナ化されたLinux(Ubuntu)環境を手に入れることができます。他にも、今回も利用している /etc/my_init.d 配下のスクリプトを初期化時に実行する機能、root以外でコマンドを実行するための setuser コマンドなど、様々な機能や仕組みを備えています。詳しくはWebページを参照ください。

phusion/passenger-dockerは、このphusion/baseimage-dockerの上に、nginxやrubyのアプリケーションサーバである Phusion Passenger をインストールしてあります。nginxはrunitの配下に設定されていますので、すぐにスーパーバイズされたデーモンとして稼働させることができます。

コンテナ初期化スクリプト

可能なことはコンテナ自身に判断させるのが良い設計です。そのためにコンテナ起動時に実行するスクリプトを組み込むことがよく行われます。今回 app コンテナで設定している初期化スクリプトの内容を見てみましょう。 /app/init/40_setup.sh を参照ください。

このスクリプトの主な役割は4つです。

  • nginxを起動可能にする
  • Railsアプリのセットアップ
  • 環境変数の引き渡し
  • DBマイグレーション

ハンズオンのため、本来はコンテナ初期化スクリプトに記述すべきでない処理もここに入っていますが、続けて詳しく説明します。

/app/init/40_setup.sh
rm -f /etc/service/nginx/down

これはrunitの機能です。サービスを定義するディレクトリ(今回は /etc/service/nginx )の直下に down という名前のファイルがあると、自動起動しません。phusion/passenger-dockerイメージ側で配置されているものですが、自動起動してほしいのでファイルを削除しています。

/app/init/40_setup.sh
chown -R app:app /var/www
cd /var/www/rails-app
setuser app bundle install --path=../vendor/bundle
if [ "$PASSENGER_APP_ENV" = 'production' ]; then
  setuser app bin/rails assets:precompile
  setuser app bundle install --path=../vendor/bundle --without test development --deployment --clean
fi

このあたりは実環境であればCIで、ビルドの一処理として適切に実施すべきものです。アプリケーションのファイルパーミッションを適切に設定し、ライブラリのインストールを行います。更にproductionモードであれば、アセットのプリコンパイルと不要なライブラリの削除を行います。

/app/init/40_setup.sh
echo "passenger_env_var 'SECRET_KEY_BASE' '$SECRET_KEY_BASE';" >> /etc/nginx/conf.d/10_setenv.conf
echo "passenger_env_var 'RDS_HOSTNAME' '$RDS_HOSTNAME';" >> /etc/nginx/conf.d/10_setenv.conf

ここは環境変数をpassengerへ引き渡すための処理です。コンテナでは環境変数を扱う機会が多くなりますので、利用するミドルウェアに合わせて設定が必要です。

/app/init/40_setup.sh
RAILS_ENV=$PASSENGER_APP_ENV setuser app bin/rails db:create db:migrate

こちらはDBのマイグレーションです。この処理も実環境であればコンテナ初期化スクリプトではなく、デプロイの手順の一貫として実施すべきものです。

次回へ

ここまでが app コンテナの設定でした。長くなりましたので、つづきは次回にしたいと思います。次回はElastic Beanstalkの設定ファイル、Dockerrun.aws.jsonを解説する予定です。

続きを読む

Mastodonでgit pullしたらビルドエラー

概要

EC2で稼働させているMastodongit pullした後にdocker-compose buildしたら下記エラーが出てハマった。

環境

  • AWS EC2(t2.medium)
  • Ubuntu Server 16.04 LTS

エラー内容

ubuntu@ip-***-***-**-**:~/mastodon$ docker-compose build
redis uses an image, skipping
db uses an image, skipping
Building streaming
Step 1/9 : FROM ruby:2.4.1-alpine
 ---> 5eadd5d1419a
Step 2/9 : LABEL maintainer "https://github.com/tootsuite/mastodon" description "A GNU Social-compatible microblogging server"
 ---> Using cache
 ---> 95a4b711ef32
Step 3/9 : ENV RAILS_ENV production NODE_ENV production
 ---> Using cache
 ---> 499e95f00e13
Step 4/9 : EXPOSE 3000 4000
 ---> Using cache
 ---> 167a91f421f4
Step 5/9 : WORKDIR /mastodon
 ---> Using cache
 ---> e185ae07f027
Step 6/9 : COPY Gemfile Gemfile.lock package.json yarn.lock /mastodon/
 ---> Using cache
 ---> 460d49537428
Step 7/9 : RUN BUILD_DEPS="     postgresql-dev     libxml2-dev     libxslt-dev     build-base"  && apk -U upgrade && apk add     $BUILD_DEPS     nodejs     libpq     libxml2     libxslt     ffmpeg     file     imagemagick  && npm install -g npm@3 && npm install -g yarn  && bundle install --deployment --without test development  && yarn --ignore-optional  && yarn cache clean  && npm -g cache clean  && apk del $BUILD_DEPS  && rm -rf /tmp/* /var/cache/apk/*
 ---> Running in 68a8d45af6e8
fetch http://dl-cdn.alpinelinux.org/alpine/v3.4/main/x86_64/APKINDEX.tar.gz
ERROR: http://dl-cdn.alpinelinux.org/alpine/v3.4/main: No such file or directory
WARNING: Ignoring APKINDEX.167438ca.tar.gz: No such file or directory
fetch http://dl-cdn.alpinelinux.org/alpine/v3.4/community/x86_64/APKINDEX.tar.gz
ERROR: http://dl-cdn.alpinelinux.org/alpine/v3.4/community: No such file or directory
WARNING: Ignoring APKINDEX.a2e6dac0.tar.gz: No such file or directory
OK: 21 MiB in 29 packages
WARNING: Ignoring APKINDEX.167438ca.tar.gz: No such file or directory
WARNING: Ignoring APKINDEX.a2e6dac0.tar.gz: No such file or directory
ERROR: unsatisfiable constraints:
  build-base (missing):
    required by: world[build-base]
  ffmpeg (missing):
    required by: world[ffmpeg]
  file (missing):
    required by: world[file]
  imagemagick (missing):
    required by: world[imagemagick]
  libpq (missing):
    required by: world[libpq]
  libxml2 (missing):
    required by: world[libxml2]
  libxml2-dev (missing):
    required by: world[libxml2-dev]
  libxslt (missing):
    required by: world[libxslt]
  libxslt-dev (missing):
    required by: world[libxslt-dev]
  nodejs (missing):
    required by: world[nodejs]
  postgresql-dev (missing):
    required by: world[postgresql-dev]
ERROR: Service 'streaming' failed to build: The command '/bin/sh -c BUILD_DEPS="     postgresql-dev     libxml2-dev     libxslt-dev     build-base"  && apk -U upgrade && apk add     $BUILD_DEPS     nodejs     libpq     libxml2     libxslt     ffmpeg     file     imagemagick  && npm install -g npm@3 && npm install -g yarn  && bundle install --deployment --without test development  && yarn --ignore-optional  && yarn cache clean  && npm -g cache clean  && apk del $BUILD_DEPS  && rm -rf /tmp/* /var/cache/apk/*' returned a non-zero code: 11

解決方法

$ git checkout $(git describe --tags `git rev-list --tags --max-count=1`)

ハマってる最中にREADMEに安定バージョン使ってねって追記されてましたとさ。。

追記

v1.2にしたところ下記のエラーが再現。調査中。

ubuntu@ip-***-**-**-***:~/mastodon$ docker-compose build
redis uses an image, skipping
db uses an image, skipping
Building streaming
Step 1/9 : FROM ruby:2.4.1-alpine
 ---> 5eadd5d1419a
Step 2/9 : LABEL maintainer "https://github.com/tootsuite/mastodon" description "A GNU Social-compatible microblogging server"
 ---> Using cache
 ---> 95a4b711ef32
Step 3/9 : ENV RAILS_ENV production NODE_ENV production
 ---> Using cache
 ---> 499e95f00e13
Step 4/9 : EXPOSE 3000 4000
 ---> Using cache
 ---> 167a91f421f4
Step 5/9 : WORKDIR /mastodon
 ---> Using cache
 ---> e185ae07f027
Step 6/9 : COPY Gemfile Gemfile.lock package.json yarn.lock /mastodon/
 ---> Using cache
 ---> 06b33c54cfd4
Step 7/9 : RUN echo "@edge https://nl.alpinelinux.org/alpine/edge/main" >> /etc/apk/repositories  && BUILD_DEPS="     postgresql-dev     libxml2-dev     libxslt-dev     build-base"  && apk -U upgrade && apk add     $BUILD_DEPS     nodejs@edge     nodejs-npm@edge     libpq     libxml2     libxslt     ffmpeg     file     imagemagick@edge  && npm install -g npm@3 && npm install -g yarn  && bundle install --deployment --without test development  && yarn --ignore-optional  && yarn cache clean  && npm -g cache clean  && apk del $BUILD_DEPS  && rm -rf /tmp/* /var/cache/apk/*
 ---> Running in 0b9005a839d9
fetch http://dl-cdn.alpinelinux.org/alpine/v3.4/main/x86_64/APKINDEX.tar.gz
ERROR: http://dl-cdn.alpinelinux.org/alpine/v3.4/main: No such file or directory
WARNING: Ignoring APKINDEX.167438ca.tar.gz: No such file or directory
fetch http://dl-cdn.alpinelinux.org/alpine/v3.4/community/x86_64/APKINDEX.tar.gz
ERROR: http://dl-cdn.alpinelinux.org/alpine/v3.4/community: No such file or directory
WARNING: Ignoring APKINDEX.a2e6dac0.tar.gz: No such file or directory
fetch https://nl.alpinelinux.org/alpine/edge/main/x86_64/APKINDEX.tar.gz
140162439957356:error:140770FC:SSL routines:SSL23_GET_SERVER_HELLO:unknown protocol:s23_clnt.c:794:
ERROR: https://nl.alpinelinux.org/alpine/edge/main: Permission denied
WARNING: Ignoring APKINDEX.65bdaf85.tar.gz: No such file or directory
OK: 21 MiB in 29 packages
WARNING: Ignoring APKINDEX.167438ca.tar.gz: No such file or directory
WARNING: Ignoring APKINDEX.a2e6dac0.tar.gz: No such file or directory
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     build-base"  && apk -U upgrade && apk add     $BUILD_DEPS     nodejs@edge     nodejs-npm@edge     libpq     libxml2     libxslt     ffmpeg     file     imagemagick@edge  && npm install -g npm@3 && npm install -g yarn  && bundle install --deployment --without test development  && yarn --ignore-optional  && yarn cache clean  && npm -g cache clean  && apk del $BUILD_DEPS  && rm -rf /tmp/* /var/cache/apk/*' returned a non-zero code: 255

続きを読む

AWS CodeDeploy 導入調査 アプリ側編

AWS CodeDeploy 導入調査 AWS 設定編 の続きになります

前回のあらすじ

  • EC2 インスタンスを作った
  • コードアップロード用の S3 Bucket を作った
  • デプロイ用の IAM ロールを作った
  • CodeDeploy アプリケーションを作った

今回はアプリ側の作業です.

デプロイ先アプリ構成

Nginx – uWsgi を sudpervisord でプロセス監視
Nginx とか supervisord とかは割とどうでもいいのですが
サーバー構成はあらかじめ一通り作成しておきます.

さらに CodeDeloy-Agent をインストールしておきます.
http://docs.aws.amazon.com/ja_jp/codedeploy/latest/userguide/codedeploy-agent-operations-install.html

とりあえずデプロイしてみる

ローカル -> S3 のアップロードは AWS-CLI を使用します.
ローカルプロジェクトのトップディレクトリで,

$ aws deploy push --application-name <<app-name>> --s3-location s3://<<s3bucket-name>>/<<app-name>>.zip --source ./ --region <<region-name>>

を実行します.
<<app-name>> は CodeDeploy で作成したアップケーション名です.

  • –ignore-hidden-files オプションで隠しファイルを無視します.
  • S3 にアップロードするファイル名は本当はなんでもいいです.
  • 圧縮時の拡張子は tar.gz でもいけるはず.

アップロードに成功すると以下のように出力されます.

To deploy with this revision, run:
aws deploy create-deployment --application-name <<app-name>> --s3-location bucket=<<s3bucket-name>>,key=<<app-name>>.zip,bundleType=zip,eTag=<<eTag>>--deployment-group-name <deployment-group-name> --deployment-config-name <deployment-config-name> --description <description>

ただし今回は成功しないと思います.

appspec.yml の作成

appspec.yml は CodeDeploy によるデプロイ作業を記述したものになります.
まずローカルプロジェクトのトップディレクトリに appspec.yml ファイルを作成し,

version: 0.0
os: linux

まで記述します. ここで,
– version は appspec のシステムバージョンで2017/04現在 0.0 のみ有効です
– os はデプロイ先 EC2 インスタンスの OS 種類で windows か linux かを設定します. linux ディストリビューションまで指定する必要はありません.

次に,

files:
   - source: /
     destination: /usr/local/src

でファイル配置を設定します.
source はコードパスで appspec.yml があるディレクリの相対パスになります.
なので source: / とした場合はディレクリ構成そのままで EC2 インスタンスの
destination に配置されます.
特定のディレクリ/ファイルのみ配置先を変えたい場合は – source: destination の記述を追加することができます.

さらに, 今回は以下の設定を追加しました.

hooks:
  AfterInstall:
    - location: copy_settings.sh
      timeout: 180
      runas: root
    - location: pip_install.sh
      timeout: 180
      runas: root
  ApplicationStart:
    - location: reload_uwsgi.sh
      timeout: 180
      runas: root

hooks 以下では CodeDeploy ライフサイクルの各処理にフックしてスクリプトを実行させることができます.
http://docs.aws.amazon.com/ja_jp/codedeploy/latest/userguide/reference-appspec-file-structure-hooks.html

CodeDeploy-Agent は Ruby で記述されており, Ruby コード上で Shell スクリプトを実行します.
今回追加した処理は

  • コード配置後に EC2インスタンス内に仕込んでおいた追加設定をコピー
  • プロジェクト内の requirements.txt の内容で pip install
  • アプリスタート時に uwsgi のリスタート

です. runas は各スクリプトの実行ユーザーです.
今回は面倒だったので全て root にしました.

デプロイに再度チャレンジ

ふたたび ローカル -> S3 のアップロード をやってみると今度は成功するはずです.
アップロードが成功したら次は AWS コンソールの CodeDeploy に移動します.

  1. ダッシュボードでアプリケーションを選択して “アクション” -> “新しいリビジョンのデプロイ”
  2. “アプリケーション”, “デプロイグループ” はそのまま, “リビジョンタイプ” は Amazon S3
  3. “リビジョンの場所” でアップロードしたソースコードを指定します.
  4. その他はそのままで “デプロイ” でデプロイ開始します.

フックスクリプトでエラーにならなければデプロイは成功するはずです.

フックスクリプトでエラーになったので解決した内容は次回

続きを読む

AWS Transit VPCソリューションを使って 手軽に マルチリージョン間 VPN環境を構築してみる

Transit VPC とは

AWS の VPC 間 VPN 接続を自動化するソリューションです。
高度なネットワークの知識がなくても、超カンタンに、世界中の リージョンにまたがる VPC を接続するネットワークを構築することができます。

概要


ある VPC を転送専用の VPN HUB(Transit VPC)として作成することで、他のVPCからのVPN接続を終端し、スター型のトポロジを自動作成します。
利用している AWSのアカウントに紐づいた VPC で VGW を作成すれば、HUBルーターに自動的に設定が投入され、VPNの接続が完了します。

予めテンプレートが用意されているので、ルーターの細かい設定を行う必要がありません。

また、高度な設定が必要な場合も、Cisco CSR1000V を利用しているので、Cisco IOS の機能は自由に利用することも可能です。

Adobe社では、大規模なネットワークを、AWS上の CSR1000V で構築しています。
https://blogs.cisco.com/enterprise/adobe-uses-cisco-and-aws-to-help-deliver-rich-digital-experiences

仕組み

  • AWS CloudFormation を使って、Transit VPC の CSR1000v のプロビジョニングが非常に簡単に行えるようになっています。

  1. VGW Poller という Lambda ファンクションが用意されており、Amazon CloudWatch を使って、Transit VPC に接続すべき VGW が存在するかを常に確認しています。
  2. VGWが存在する場合、VGW Poller が必要な設定を行い、設定情報を Amazon S3 bucket に格納します
  3. Cisco Configurator という名前の Lambda ファンクションが用意されており、格納した設定情報から、CSR1000v 用の設定を作成します
  4. Cisco Configurator が Transit VPC の CSR1000v へ SSH でログインし設定を流し込みます。
  5. VPN接続が完了します。

詳細については、下記、ご参照ください。
– AWS ソリューション – Transit VPC
https://aws.amazon.com/jp/blogs/news/aws-solution-transit-vpc/
– Transit Network VPC (Cisco CSR)
https://docs.aws.amazon.com/solutions/latest/cisco-based-transit-vpc/welcome.html

Transit VPC 構築方法

基本は、Wizard に従い、3(+1)ステップで設定が可能です。

事前準備 – CSR1000V用 Key Pair の作成

CSR1000V へログインする際に使う、Key Pair を EC2 で一つ作っておきましょう。
EC2 > Network & Security > Key Pairs から作成できます。名前はなんでもいいです。

.pem ファイルが手に入るので、後ほど、CSR1000V へログインする際にはこれを使います。

Step 1. Cisco CSR1000v ソフトウェア利用条件に同意

AWS マーケットプレイスの下記のページから、リージョンごとの値段が確認できます。

https://aws.amazon.com/marketplace/pp/B01IAFXXVO

  • For Region で 好きなリージョンを選択
  • Delivery Method で Transit Network VPC with the CSR 1000v を選択

その後 Continue

  • Manual Launch タブが選択されていること
  • Region / Deployment Options が先に設定したものとなっていること

上記を確認し、Accept Software Terms をクリックします。

Step 2. Transit VPC スタックの起動

下記のページより、Transit VPC 用の CloudFormation を起動することで、Transit VPC に必要な CSR1000v をセットアップすることができます。

http://docs.aws.amazon.com/ja_jp/solutions/latest/cisco-based-transit-vpc/step2.html

上記ページから Launch Solution をクリックします。
CloudFormation のページが立ち上がるので、まず、VPN HUB を 設置するリージョンになっているか確認します。
このソリューションは、Lambda を使うので、Transit VPC を設置できるのは、Lambda が使えるリージョンに限ります。東京は対応してます。
Lambda 対応リージョンは、こちらで確認できます。
https://aws.amazon.com/about-aws/global-infrastructure/regional-product-services/

正しいリージョンになっていたら、設定を進めます。

2-1. Select Template

テンプレートがすでに選択された状態になっていると思うので、特に設定の必要なし

Next をクリック

2-2. Specify Details

幾つかのパラメーターがありますが、最低限下記を変更すれば、動作します。

  • Specify Details

    • Stack name を設定します。
  • Parameters
    - Cisco CSR Configuration

    • SSH Key to access CSR で、事前準備で作成した key を選択します。
    • License Modelで、BYOL (Bring Your Own License) もしくは License Included を選択します。

CSR1000v のライセンスについて、Cisco から購入したものを使う場合は、BYOL を選択します。
ライセンス費用も利用料に含まれた利用形式が良ければ、License included version を選択します。
検証ライセンスがあるので、テストの場合は、BYOL で良いかと思います

入力が完了したら、 Next

2-3. Options

特に設定の必要なし Next をクリック

2-4. Review

  • 設定を確認して、一番下の acknowledge のチェックボックスをクリック

その後、Create で CSR1000V のインスタンス作成・セットアップが始まります

5分ほどすると、CSR1000V が 2インスタンス 立ち上がります。

事後設定(オプション)

起動した CSR1000V は デフォルトで、Lambda ファンクションからのログインのみを許可する設定になっているので、ssh で CLI にアクセスしたい場合は、Security Group の設定を変更します。

EC2 のダッシュボードから CSR1000V を選択し、Security Group の設定で SSH を許可します。
すべてのPCからSSHを受ける場合は、ソースアドレスとして 0.0.0.0/0 を指定します。

設定後、ssh でログインするには、事前準備で作成した キーペアで取得した .pem ファイルのパーミッションを変更します。

chmod 400 <キーペア名>.pem

これを使って、下記のコマンドで CSR1000V にログインできます

ssh -i <キーペア名>.pem <CSR1000V のパブリックIP>

ログインすれば、CSR1000v であることがわかると思います。

ip-XXX-XXX-XXX-XXX #sh ver
Cisco IOS XE Software, Version 16.03.01a
Cisco IOS Software [Denali], CSR1000V Software (X86_64_LINUX_IOSD-UNIVERSALK9-M), Version 16.3.1a, RELEASE SOFTWARE (fc4)
Technical Support: http://www.cisco.com/techsupport
Copyright (c) 1986-2016 by Cisco Systems, Inc.
Compiled Fri 30-Sep-16 02:53 by mcpre

<省略>

Step 3. スポーク VPC のタグ付け

上記、CSR1000V が立ち上がれば、あとは、Spoke VPC の VGW でタグを付けるだけで、CSR1000V への VPN 接続が完了します。

3-1. Spoke VPC の作成

新たに Spoke VPC を作成する場合は、下記の手順で作ります。

  • 好きなリージョンに、VPC を作成します。

    • VPC Dashboard > Virtual Private Cloud > Your VPC > Create VPC で作成します。
  • Virtual Private Gateway(VPG) を作成します。
    • VPC Dashboard > VPN Connection > Virtual Private Gateways > Create Virtual Private Gateway で作成します。
  • 作成した VPG を、先程作成した VPCにアタッチします。
    • VPC Dashboard > VPN Connection > Virtual Private Gateways > Attach to VPC  から、VPCへVGWをアタッチします。

3-2. VGW のタグ付け

  • 先程作成した VGW を選択し、下部の Tags タブを選択します。

    • Edit をクリックし Tag を追加します。

デフォルトの設定では、下記のタグを利用する設定になっていますので、下記タグを追加します
Key = transitvpc:spoke
Value = true

上記の設定が完了すると、VGWと Step2. で作成した、2台の CSR1000Vの間で自動的に VPN 接続が確立します。

http://docs.aws.amazon.com/ja_jp/solutions/latest/cisco-based-transit-vpc/step3.html

Step 4. 他の AWS アカウントからの接続設定 (オプション)

http://docs.aws.amazon.com/ja_jp/solutions/latest/cisco-based-transit-vpc/step4.html

まとめ

AWS の Transit VPC を使えば、世界中 にまたがる AWS の 各リージョンのVPCを簡単に VPN 接続できます。

また、VPN HUB ルーターは Cisco CSR1000v なので、企業内のシスコルーターと VPN 接続すれば、DC を AWS にして、世界中にまたがる VPN ネットワークを構築することができます。
ダイレクトコネクトとも連携可能です。

参考

On board AWS TransitVPC with Cisco CSR1000v (英語ですが、手順がわかりやすいです)

Cisco CSR 1000v: Securely Extend your Apps to the Cloud
https://www.slideshare.net/AmazonWebServices/cisco-csr-1000v-securely-extend-your-apps-to-the-cloud

続きを読む

Travis CI + s3でデプロイしてみた。

Travis CIからs3にデプロイした時に、詰まったのでメモ。

Travis CIとは

「継続的インテグレーション(CI)」ツール。
あらかじめ指定したgithubのレポジトリに、コードをpushすると、自動でテストを行ってくれる。
テストが成功すれば指定したホスティングサービスにデプロイもしてくれる。失敗するとメール等で通知してくれる、テスト自動化ツール。

手順

前提条件

・GitHub のアカウントを持っている
・GitHub にリポジトリを持っている
・Travis CI のアカウントを持っている
・Travis CI の CLI をインストールしている (gem install travis)
・AWS のアカウントを持っている
・s3の更新権限を持ったアクセスIDとSecrete keyをIAMで作っている。
・s3のバケットを、静的サイトをしてホスティングしている。

1.https://travis-ci.org/ にログインして当該リポジトリをONにする。
2.ローカルのプロジェクトフォルダで、$ touch .travis.yml
3.$Travis encrypt "アクセスキーID"$Travis encrypt "シークレットアクセスキー"で、ターミナルに出てきた、secure: "..."を.travis.ymlに貼り付ける。

travis.yml
language: node_js
script: echo "do nothing"
deploy:
  provider: s3
  access_key_id:
    secure: "アクセスキーID"
  secret_access_key:
    secure: "シークレットアクセスキー"
  bucket: s3-website.shikumi-zukuri.com
  region: us-east-1
  endpoint: s3.amazonaws.com
  on:
    branch: master

4.git add .git commitgit pushする。

これで、Travis CIが、自動でテストを実行してくれ指定したs3バケットに、htmlとかのファイルをデプロイしてくれる。

参考
公式ドキュメント
Travis CIs3 Deployment
Travis CI for Complete Beginners

その他
# travis-ciからAmazon S3へファイルをデプロイする
GitHub + Travis CI + Amazon S3 で git push で更新されるサイトをつくった

サンプルコード(github)

続きを読む

爆速API構築〜chalice編〜

爆速でAPIをリリースしたい方へ送ります

https://github.com/awslabs/chalice

chaliceとは

聖杯の名を冠するこのchaliceはフレームワークというよりはツールで、アプリケーションコードさえあれば、AWS Lambda、AWS APIGateway、IAMRoleなどの設定をよしなにやって、AWS上にデプロイをキメてくれるという活かしたシロモノです。これにより爆速でAPIを構築して、プロダクションリリースを実現します。

まずはじめに

兎にも角にもAWSのサービスをフルフル使ってAPI構築していきますので、credentialの設定をまずはじめに行っておく必要があります。

$ mkdir ~/.aws
$ cat >> ~/.aws/config
[default]
aws_access_key_id=YOUR_ACCESS_KEY_HERE
aws_secret_access_key=YOUR_SECRET_ACCESS_KEY
region=ap-northeast-1

複数のAWSアカウントを切り替えてお使いの方は、direnvなどで環境変数にてACCESSKEYを設定しておくことをオススメいたします。SDKによりますが、今回使うboto3に関してはAWSCliとコンパチな感じの優先度でcredentialや環境変数の読んでいるっぽいので、ここらへんの記事を参照されると幸せになれるかもしれません。

プロジェクト作成からのデプロイキメる方法

下記のようにコマンドラインにぶち込んでみましょう

$ pip install chalice
$ chalice new-project helloworld && cd helloworld
Initial creation of lambda function.
Creating role
Creating deployment package.
Lambda deploy done.
Initiating first time deployment...
Deploying to: dev
https://endpoint/dev/

$ curl https://endpoint/dev
{"hello": "world"}

上記の一連の作業は、プロジェクトを新規作成後、すぐデプロイをしています。
chalice deploy という魔法の一言で、プロジェクトを AWS Lambda にデプロイして、 AWS API GatewayAWS Lambda の紐付けをよしなにやってパブリックにアクセス可能な状態にデプロイしてくれるのです。

APIの内容をごちゃごちゃしたい場合は、 新規作成時に作成される app.py の中身を本能のままにいじっていきましょう

S3にログを吐き出すAPIを作る方法

自分の周りだととりあえずログを溜めておくAPIが欲しい、みたいな要件が多いです
とりあえずS3にJSONで保存しておいて後でサルベージするなりなんなり、というケースが多々あります
特に今はAWS AthenaでJSONの集計が対話的にできたりみたいな事があったりしてことさらその要件でのお話を頂くことが多いです

ではAPIにJSONをPOSTするとその形式でJSONをS3に書いてくれるようなAPIを作成してみましょう

まずS3上にbucketを作っておきましょう(これは手動で作業が必要です)
そしてAWSSDKをinstallしましょう

$ pip install boto3

app.py を下記のように書き換えてみましょう

app.py
from chalice import Chalice

app = Chalice(app_name='helloworld')
import json
import boto3
from botocore.exceptions import ClientError

from chalice import NotFoundError

S3 = boto3.client('s3', region_name='ap-northeast-1')
BUCKET = 'your-bucket-name'

@app.route('/objects/{key}', methods=['GET', 'PUT'])
def s3objects(key):
    request = app.current_request
    if request.method == 'PUT':
        S3.put_object(Bucket=BUCKET, Key=key,
                      Body=json.dumps(request.json_body))
    elif request.method == 'GET':
        try:
            response = S3.get_object(Bucket=BUCKET, Key=key)
            return json.loads(response['Body'].read())
        except ClientError as e:
            raise NotFoundError(key)

書き換えたらデプロイしてみましょう

$ chalice deploy
Updating IAM policy.

The following actions will be added to the execution policy:

s3:GetObject
s3:PutObject

Would you like to continue?  [Y/n]: Y
Updating lambda function...
Regen deployment package...
Sending changes to lambda.
Lambda deploy done.
API Gateway rest API already found.
Deleting root resource id
Done deleting existing resources.
Deploying to: dev
https://endpoint/dev/

サラッとYを入力してデプロイしてしまいましたが、実はここでIAMRoleの設定を chalice がよしなにやってくれています
詳しく説明すると、デプロイ時にデプロイ対象のソースコードをパースして、必要な権限を割り出して、その権限、つまり下記の二つの権限を設定しても良いか聞いてくれています

  • s3:GetObject
  • s3:PutObject

そしてその権限をIAMに設定して、LambdaからS3へアクセスできるような状態でデプロイをキメてくれます
つまりアプリケーション構築する人間はIAMの設定を意識することなく、IAMの設定がなされた上でデプロイされます

なんて恐ろしい素晴らしい気の利かせ方でしょうか!!
IAMの設定はすごいめんどくさいですし、えーいAdminつけとけみたいな話にもなりかねないので、自動で適切に設定してくれるとなると嬉しい限りです

補足〜健康的なPythonでの開発のために〜

Pythonは2.X系と3.X系の乖離があり世界に深い悲しみがあります
AWS Lambda上のPythonは2.7系なので3.X系と違います
そのため、手元の環境を合わせた方が良い、というケースが多々生じます

そんな深い悲しみから決別するために手元の開発環境を任意の環境に切り替えるために
pyenvを入れておきましょう

続きを読む

AWS上でMongoDBを動かす

MongoDBに関する基本的な内容をまとめてみたものです。MongoDBに関する、Web上にすでにある良識な解説コンテンツをまとめたまとめサイトの抜粋です。
AWS上でMongoDBを動かす

AWSであれば、MongoDB環境を容易に構築できる

AWS MarketPlaceには、MongoDB環境を構築するために必要なミドルウェアがプリインストールされたOSイメージが多数あります。
※MongoDBの開発元である 10gen (現MongoDB Inc.)もMongoDB入りイメージを無償提供中

基本的に、それらのイメージをもとにAWSのインスタンスを立ち上げればMongoDB環境ができあがります。英文ですが、下記に具体的な構築手順があります。
http://www.mongodb.org/display/DOCS/AWS+Marketplace

AWSの複数ゾーンとレプリカを組み合わせればDRも容易

MongoDBは、マスタ/スレープ方式のレプリケーションに対応しています。

世界中のデータセンターから選択できる、AWSのさまざまなリージョンやアベイラビリティゾーンを複数選択してMongoDBのレプリカ機能を使用すれば、DR (Disaster Recovery)対応も可能です。

AWSは12のリージョンに、合計で33のアベイラビリティゾーンで運用されています (2016年5月現在)
https://aws.amazon.com/jp/about-aws/global-infrastructure/
AWSのリージョンは、最低でも2つのAZ(アベイラビリティゾーン)をもっていて、それぞれのAZはお互いに地理的・電源的・ネットワーク的に分離されつつも、AZ間は高速専用線で接続されています。

一方のゾーンにMongoDBおよびMongoDBのArbiterインスタンスを立ち上げ、もう一方のゾーンにMongoDBインスタンスを立ち上げれば、片方のゾーンで地震等の災害があっても、データが残り、そのままMongoDBは機能し続けます。

シャードとレプリカを組み合わせたMongoDBクラスタ構成

MongoDBでは、基本的に、シャードを増やすことにより水平スケールさせ、レプリカにより可用性を実現します。各シャードをレプリカセットにすることにより、高い可用性を実現しながら、水平スケールさせた大規模なデータベースを構成することができます。

開発段階では、1 つのレプリカセットから始めることもできますし、本稼働中に 3 つのレプリカセットに移行することもできます。下記URLに、AWS上でMongoDB環境を構築するアーキテクチャ例が示されています。
http://docs.aws.amazon.com/ja_jp/quickstart/latest/mongodb/architecture.html
・図1: レプリケーション係数 3 の MongoDB リファレンスデプロイ
・図2: 3つのレプリカセット2方向シャーディングを使用するAWSのMongoDBクラスター

MongoDBをAWS上で動くようにするまでの手順

AWSにて、MongoDBを動くようにするまでの手順は、概略、下記の通り:

・EC2インスタンスおよびEBSボリュームを用意

・Amazon VPC をセットアップ

*Amazon VPC 内のプライベートサブネットとパブリックサブネット、NAT インスタンス、
セキュリティ グループ、IAM ロールなど、MongoDB のデプロイ中に必要な様々な
ネットワークリソースを作成

・Amazon EBS をセットアップして MongoDB を保存。

・MongoDB 設定をカスタマイズするオプションを指定した後、MongoDBを起動。

MongoDB のバージョン番号 (2.6 または 3.0)、レプリカセットの数 (1 または 3)、シャード数
(0、1、2、または 3)、インスタンスあたりのマイクロシャード数を選択することができます。

※より詳細は、下記を参照ください。
[AWS上の MongoDB] http://docs.aws.amazon.com/ja_jp/quickstart/latest/mongodb/deployment.html

続きを読む

linebot-serverless-blueprint-javaの作り方(その1)

linebot-serverless-blueprint-javaを作った!で紹介したLINE BOTの雛形の作り方を何回かに分けて紹介します。

環境

  • Windows 10
  • Node: v6.9.1
  • npm: 3.10.8
  • Git for Windows: 2.9.3.windows.2
  • Java 8
  • AWSアカウント(AdministratorAccess権限)
    ※rootアカウントはやめましょう

前準備~serverlessの導入

プロジェクト用フォルダーの作成

mkdir linebot-serverless-blueprint-java
cd linebot-serverless-blueprint-java

package.jsonの作成

npm init -y
package.json
{
  "name": "linebot-serverless-blueprint-java",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo "Error: no test specified" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}

serverlessのインストール

npm install serverless --save-dev

“devDependencies”が追加されます。

package.json
{
  "name": "linebot-serverless-blueprint-java",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo "Error: no test specified" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "serverless": "^1.8.0"
  }
}

serverlessプロジェクトの作成

node_modules.binserverless create -t aws-java-gradle

なぜかgradlewrappergradle-wrapper.jarが作成されませんので、個別にダウンロードします。
https://github.com/serverless/serverless/blob/master/lib/plugins/create/templates/aws-java-gradle/gradle/wrapper/gradle-wrapper.jar
こんな感じになります。

C:.
│  .npmignore
│  build.gradle
│  gradlew
│  gradlew.bat
│  package.json
│  serverless.yml
│  
├─gradle
│  └─wrapper
│          gradle-wrapper.jar
│          gradle-wrapper.properties
│          
├─node_modules
~~~省略~~~
│              
└─src
    └─main
        ├─java
        │  └─com
        │      └─serverless
        │              ApiGatewayResponse.java
        │              Handler.java
        │              Response.java
        │              
        └─resources
                log4j.properties

Javaプロジェクトのフォルダー構成の変更

今回はJavaプロジェクトを2つ用意しますので、フォルダー構成を変更します。

srcフォルダーとbuild.gradleをサブフォルダー内に移動

mkdir webhook
move src webhook
        1 個のディレクトリを移動しました。
move build.gradle webhook
        1 個のファイルを移動しました。

もう一つのJavaプロジェクト用ファイルもコピーして作成

xcopy /E /I webhook reply
webhookbuild.gradle
webhooksrcmainjavacomserverlessApiGatewayResponse.java
webhooksrcmainjavacomserverlessHandler.java
webhooksrcmainjavacomserverlessResponse.java
webhooksrcmainresourceslog4j.properties
5 個のファイルをコピーしました

settings.gradleファイルの作成

type nul > settings.gradle
settings.gradle
include 'webhook','reply'

Gradle動作確認

gradlew projects
------------------------------------------------------------
Root project
------------------------------------------------------------

Root project 'linebot-serverless-blueprint-java'
+--- Project ':reply'
--- Project ':webhook'

To see a list of the tasks of a project, run gradlew <project-path>:tasks
For example, try running gradlew :reply:tasks

BUILD SUCCESSFUL

Total time: 7.01 secs

build.gradleファイルの修正

webhook/build.gradleを少し修正します。reply/build.gradleも同様(baseNameはreply)に修正します。

webhook/build.gradle
apply plugin: 'java'

repositories {
    mavenCentral()
}

sourceCompatibility = 1.8
targetCompatibility = 1.8

+tasks.withType(AbstractCompile)*.options*.encoding = tasks.withType(GroovyCompile)*.groovyOptions*.encoding = 'UTF-8'

dependencies {
    compile (
        'com.amazonaws:aws-lambda-java-core:1.1.0',
        'com.amazonaws:aws-lambda-java-log4j:1.0.0',
+        'com.amazonaws:aws-java-sdk-dynamodb:1.11.98',
+        'com.linecorp.bot:line-bot-api-client:1.6.0',
    )
    testCompile 'junit:junit:4.12'
}

// Task for building the zip file for upload
task buildZip(type: Zip) {
    // Using the Zip API from gradle to build a zip file of all the dependencies
    //
    // The path to this zip file can be set in the serverless.yml file for the
    // package/artifact setting for deployment to the S3 bucket
    //
    // Link: https://docs.gradle.org/current/dsl/org.gradle.api.tasks.bundling.Zip.html

    // set the base name of the zip file
-    baseName = "hello"
+    baseName = "webhook"
    from compileJava
    from processResources
    into('lib') {
        from configurations.runtime
    }
}

build.dependsOn buildZip

以上で下準備は完了です。
次回はServerlessの設定やJavaプログラムについての解説を行いたいと思います。

続きを読む