Setting Up an Envoy Front Proxy on Amazon ECS | AWS Compute Blog

AWS Compute Blog
Setting Up an Envoy Front Proxy on Amazon ECS
This post was contributed by Nare Hayrapetyan, Sr. Software Engineer
Many customers are excited about new microservices management tools and technologies like service mesh. Specifically, they ask how to get started using Envoy on AWS…. 続きを読む

Setup AWS server with SSL + other related setting

さらに表示: aws server setup, setup email server aws, aws setup smtp server, smtp server setup aws, setup proxy server aws, aws setup mail server, setup web server amazon aws, setup aws server, setup php server verification email, webmin setup sendmail server, dedicated server ssl installation, … 続きを読む

AWS AppSyncとReactでToDoアプリを作ってみよう(3) Reactアプリの作成

はじめに

前回の記事まででは、AWS AppSyncを使ってGraphQL APIを作成しました。
今回は、そのGraphQL APIと連携するクライアント側Reactで作成してきたいと思います。
AWS AppSyncでは、React向けのGraphQLクライアントのApolloに対応した、aws-appsync-react (バインディングライブラリ)が用意されているので、今回はこれを使って、AWS AppSyncのデータとコンポーネントの紐付けを行っていきます。

プロジェクトのセットアップ

雛形の作成

Create React Appを使って、雛形を作成します。
(今回使用したnodeのバージョンは9.2.0です。)

$ mkdir aws-appsync-todo-app
$ npx create-react-app .

追加で必要なパッケージをインストールします。

$ yarn add graphql-tag react-apollo aws-appsync aws-appsync-react uuid
  • graphql-tag

    • GraphQLのスキーマをJavaScriptのコード内に定義するために使用
  • react-apollo
    • GraphQLクライアント
  • aws-*のパッケージ
    • AWS AppSyncとApolloを連携するために使用
  • uuid
    • Todo個々のアイテムにクライアント側でユニークなIDをつけるために使用

設定ファイルの取得とインポート

コンソール画面から、「AWS AppSync > 作成したプロジェクト > Top画面」を開き、「Getting Started」の一番下にある、「Download the AWS AppSync.js config file」からAppSync.jsをダウンロードします。

スクリーンショット 2018-01-25 22.17.20.png

ダウンロードしたファイルを、作成したプロジェクトのsrc以下に配置し、他のパッケージと合わせてApp.jsにインポート

App.js
import { ApolloProvider } from 'react-apollo';
import AWSAppSyncClient from "aws-appsync";
import { Rehydrated } from "aws-appsync-react";
import appSyncConfig from "./AppSync";

AppSyncClientを初期化

設定ファイルから読み込んだ、AWS認証情報・API情報を引数に、AWS AppSyncClientを初期化します。
authパラメータで認証方式を選択できますが、今回はAPI Keyによる認証を使用します。

App.js
// AWS AppSync Client
const client = new AWSAppSyncClient({
  url: appSyncConfig.graphqlEndpoint,
  region: appSyncConfig.region,
  auth: {
    type: appSyncConfig.authenticationType,
    apiKey: appSyncConfig.apiKey,
  }
});

AppSyncのデータと連携するコンポーネントをApolloProviderRehydratedに含めApolloProviderに対して、AppSyncClientを渡しています。

App.js
class App extends Component {
  render() {
    return (
      <ApolloProvider client={client}>
        <Rehydrated>
          <div className="App">
            <header className="App-header">
              <h1 className="App-title">AWS AppSync Todo</h1>
            </header>
            <TodoListWithData />
          </div>
        </Rehydrated>
      </ApolloProvider>
    );
  }
}

GraphQLクエリの作成

graphql-tagのgqlメソッドを使って、クエリを定義します。今回は、src/GraphQL以下に作成しました。

Todo全件取得のQuery

QueryGetTodos.js
import gql from "graphql-tag";

export default gql(`
query {
  getTodos {
    id
    title
    description
    completed
  }
}`);

Todo作成のMutation

MutationAddTodo.js
import gql from "graphql-tag";

export default gql(`
mutation addTodo($id: ID!, $title: String, $description: String, $completed: Boolean) {
  addTodo(
    id: $id
    title: $title
    description: $description
    completed: $completed
  ) {
    id
    title
    description
    completed
  }
}`);

Todo更新のMutation

MutationUpdateTodo.js
import gql from "graphql-tag";

export default gql(`
mutation updateTodo($id: ID!, $title: String, $description: String, $completed: Boolean) {
  updateTodo(
    id: $id
    title: $title
    description: $description
    completed: $completed
  ) {
    id
    title
    description
    completed
  }
}`);

Todo削除のMutation

MutationDeleteTodo.js
import gql from "graphql-tag";

export default gql(`
mutation deleteTodo($id: ID!) {
  deleteTodo(id: $id) {
    id
    title
    description
    completed
  }
}`);

ToDoList Componentの実装

今回は、ざっくり1つのComponentにTodoリストの全機能をまとめてしまいます。
src/Components以下に、TodoList.jsを作成しました。

AWS AppSyncとComponentの連携

AWS AppSyncのGraphQL APIからとReact Componentを連携するために、react-apolloを使用します。

react-apolloのgraphqlメソッドの引数にComponentを渡すと、ComponentのpropsでGraphQL APIから取得したデータを取得できるComponentを受け取ることができます。

graphql
const TodoListWithData = graphql(QueryGetTodos)(TodoList);

また、複数のQuery、MutationとComponentを連携する場合には、react-apolloのcomposeメソッドを使用します。
実際には、それぞれにオプションなどを指定するため、あくまでイメージです。

compose
const TodoListWithData = compose(
  graphql(QueryGetTodos),
  graphql(MutationAddTodo),
  graphql(MutationUpdateTodo),
  graphql(MutationDeleteTodo),
)(TodoList);

実際に、それぞれのQuery、Mutationを紐付ける部分は次の通りです。

TodoList.js
export default compose(
  // 全件取得Query
  graphql(QueryGetTodos, {  // あらかじめ定義したGraphQLクエリを使用
    options: {
      fetchPolicy: 'cache-and-network'
    },
    props: (props) => ({
      todos: props.data.getTodos
    })
  }),
  // 追加Mutation
  graphql(AddTodoMutation, {  // あらかじめ定義したGraphQLクエリを使用
    props: (props) => ({
      onAdd: (todo) => {
        props.mutate({
          variables: { ...todo },
          // APIからのレスポンスが返ってくるまえにpropsに反映する値を設定
          optimisticResponse: () => ({ addTodo: { ...todo, __typename: 'Todo' } })
        })
      }
    }),
    options: {
      // 追加の後に全件リストを更新するアクション
      refetchQueries: [{ query: QueryGetTodos }],
      update: (proxy, { data: { addTodo } }) => {
        const query = QueryGetTodos;
        const data = proxy.readQuery({ query });

        data.getTodos.push(addTodo);

        proxy.writeQuery({ query, data });
      }
    }
  }),
  // 状態更新(チェック)Mutation
  graphql(UpdateTodoMutation, {  // あらかじめ定義したGraphQLクエリを使用
    props: (props) => ({
      onCheck: (todo) => {
        props.mutate({
          variables: { id: todo.id, title: todo.title, description: todo.description, completed: !todo.completed },
          // APIからのレスポンスが返ってくるまえにpropsに反映する値を設定
          optimisticResponse: () => ({ updateTodo: { id: todo.id, title: todo.title, description: todo.description, completed: !todo.completed, __typename: 'Todo' } })
        })
      }
    }),
    options: {
      // 更新の後に全件リストを更新するアクション
      refetchQueries: [{ query: QueryGetTodos }],
      update: (proxy, { data: { updateTodo } }) => {
        const query = QueryGetTodos;
        const data = proxy.readQuery({ query });

        data.getTodos = data.getTodos.map(todo => todo.id !== updateTodo.id ? todo : { ...updateTodo });

        proxy.writeQuery({ query, data });
      }
    }
  }),
  // 削除Mutation
  graphql(DeleteTodoMutation, {  // あらかじめ定義したGraphQLクエリを使用
    props: (props) => ({
      onDelete: (todo) => props.mutate({
        variables: { id: todo.id },
        // APIからのレスポンスが返ってくるまえにpropsに反映する値を設定
        optimisticResponse: () => ({ deleteTodo: { ...todo, __typename: 'Todo' } }),
      })
    }),
    options: {
      // 削除の後に全件リストを更新するアクション
      refetchQueries: [{ query: QueryGetTodos }],
      update: (proxy, { data: { deleteTodo: { id } } }) => {
        const query = QueryGetTodos;
        const data = proxy.readQuery({ query });

        data.getTodos = data.getTodos.filter(todo => todo.id !== id);

        proxy.writeQuery({ query, data });
      }
    }
  })
)(TodoList);

それ以外の部分は次の通りです。

TodoList.js
class TodoList extends Component {

  constructor(props) {
    super(props);
    this.state = {
      todo: {
        title: '',
        description: ''
      },
    };
  }

  // propsの初期値を設定
  static defaultProps = {
      todos: [],
      onAdd: () => null,
      onDelete: () => null,
      onUpdate: () => null,
  }

  todoForm = () => (
    <div>
      <span><input type="text" placeholder="タイトル" value={this.state.todo.title} onChange={this.handleChange.bind(this, 'title')} /></span>
      <span><input type="text" placeholder="説明" value={this.state.todo.description} onChange={this.handleChange.bind(this, 'description')} /></span>
      <button onClick={this.handleOnAdd}>追加</button>
    </div>
  );

  renderTodo = (todo) => (
    <li key={todo.id}>
      <input type="checkbox"checked={todo.completed} onChange={this.handleCheck.bind(this, todo)} />
      {!todo.completed && todo.title}
      {todo.completed && (<s>{todo.title}</s>)}
      <button onClick={this.handleOnDelete.bind(this, todo)}>削除</button>
    </li>
    );

  handleChange = (field, { target: { value }}) => {
    const { todo } = this.state;
    todo[field] = value;
    this.setState({ todo });
  }

  handleOnAdd = () => {
    if (!this.state.todo.title || !this.state.todo.description) {
      return;
    }
    const uuid = uuidv4();
    const newTodo = {
      id: uuid,
      title: this.state.todo.title,
      description: this.state.todo.description,
      completed: false
    }
    this.props.onAdd(newTodo);

    const { todo } = this.state;
    todo.title = '';
    todo.description = '';
    this.setState({ todo });
  }

  handleCheck = (todo) => {
    this.props.onCheck(todo);
  }

  handleOnDelete = (todo) => {
    this.props.onDelete(todo);
  }

  render() {
    const { todos } = this.props;
    return (
      <Fragment>
        {this.todoForm()}
        <ul>
          {todos.map(this.renderTodo)}
        </ul>
      </Fragment>
    );
  }
}

参考

Building a ReactJS Client App -AWS AppSync
ReactとApolloを使ってGithub GraphQL APIを試してみる -Qiita
APOLLO CLIENT -Apollo

まとめ

クライアント画の実装に関しては、react-apolloに依存する部分が多く、AWS AppSyncとReactの組み合わせをガッツリ使っていこうとすると、react-apolloのヘルパーメソッドやキャッシュなどのオプション周りを詳しく見ていく必要があるかと思います。
(逆にそれ以外の部分は、aws-appsync-reactがよしなにやってくれるので、気にする必要はない)
今回は、GraphQLクエリにQueryとMutationのみを使用しましたが、機会があれば、Subscriptionを使ってリアルタイムでサーバー側と通信を行うパターンも試してみたいと思います。

続きを読む

Hadoop dev with Aws and Spark Implementation:Proxy

さらに表示: amazon machine learning vs spark, aws spark tutorial, aws machine learning collaborative filtering, azure recommender systems, aws collaborative filtering, aws recommendation engine 2017, aws machine learning recommendation engine, build a recommendation engine using amazon … 続きを読む

Linux のログイン・ログオフ履歴を Cloudwatch Logs に送信する

サマリ

Linux のログイン/ログオフの履歴(だけ)を Cloudwatch Logs に送りたかった。
rsyslog から sshd のログだけ抽出して Cloudwatch Logs Agent で送った。できた。

要件

Linux へのログイン・ログオフの履歴を Cloudwatch Logs に保存する必要があり、Cloudwatch Logs Agent をインストールして /var/log/secure を Cloudwatch Logs に送信する。
ただし、トラフィック量の都合で secure 全て送るのはよろしくないのでいい感じに絞ったものを送信したい。

SSH ログイン時に出力されるログには2種類あり、

  1. sshd プロセスが出力する rsyslog

    • /var/log/secure
  2. login プロセス出力するログ達(バイナリ形式)
    • /var/log/wtmp (ログイン成功ログ)

      • last コマンドで表示、新しいものが上で並ぶ
    • /var/log/btmp (ログイン失敗ログ)
      • lastb コマンドで表示、新しいものが上で並ぶ

送信するにはテキストである必要があるため、

  1. rsyslog からうまいこと sshd プロセスのログだけを別ファイルにする

    • rsyslog で出力されたログをCloudwatch Logs Agent で送信する
  2. last/lastbコマンドを実行し、結果をログファイルに出力するシェルスクリプトを作成する。その際、時系列降順に直す必要がある。
    • cronで定期的に実行し、ログをCloudwatch Logs Agent で送信する

の2パターン考えられるが、楽そうな前者を試す。

設定手順

環境

  • Red Hat Enterprise Linux 7.4 (HVM)
  • awscli-cwlogs 1.4.4

SSHログの抽出

適当な EC2 インスタンスを起動。

要件としては、rsyslog の secure ログ /var/log/secure| grep 'sshd'したような結果が出力できればよさそう。そのほかの secure ログはいらない。

console
$ sudo cat /var/log/secure | grep 'sshd'
略
Jan 23 19:41:46 HOSTNAME sshd[5106]: Server listening on 0.0.0.0 port 22.
Jan 23 19:41:46 HOSTNAME sshd[5106]: Server listening on :: port 22.
Jan 23 20:40:54 HOSTNAME sshd[1976]: pam_unix(sshd:session): session closed for user ec2-user
Jan 23 20:47:46 HOSTNAME sshd[4914]: Accepted publickey for ec2-user from 10.0.0.2 port 61646 ssh2: RSA SHA256:xxx
Jan 23 20:47:46 HOSTNAME sshd[4914]: pam_unix(sshd:session): session opened for user ec2-user by (uid=0)
Jan 23 20:49:12 HOSTNAME sshd[4914]: pam_unix(sshd:session): session closed for user ec2-user

rsysgにはプロパティベース フィルタというものがあり、 :property, [!]compare-operation, "value"
programname でフィルタがかけられる。これを利用すれば特定のプロセスのログだけ別ファイルに出力することが可能。
なので rsyslog の設定をしていく。secure_sshd という新しいログファイルに sshd プロセスのログだけを出力する設定を追記。

/etc/rsyslog.conf
# sshd ログを別ファイルにも出力
:programname, isequal, "sshd" /var/log/secure_sshd
console
sudo service rsyslog restart

ログイン・ログオフしてから良い感じにログが出ていること確認できた。

console
$ sudo cat /var/log/secure_sshd
Jan 24 03:08:55 HOSTNAME sshd[9308]: Accepted publickey for ec2-user from 10.0.0.3 port 60196 ssh2: RSA SHA256:xxx
Jan 24 03:08:55 HOSTNAME sshd[9308]: pam_unix(sshd:session): session opened for user ec2-user by (uid=0)
Jan 24 03:09:14 HOSTNAME sshd[9308]: pam_unix(sshd:session): session closed for user ec2-user

Cloudwatch Agent 側設定

EC2インスタンスに CloudwatchLogs 用のポリシーをアタッチ。

Send2Cloudwatch
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "logs:CreateLogGroup",
        "logs:CreateLogStream",
        "logs:PutLogEvents",
        "logs:DescribeLogStreams"
    ],
      "Resource": [
        "arn:aws:logs:*:*:*"
    ]
  }
 ]
}

パッケージ更新、awslogsインストール

console
sudo yum update -y
# ubuntu,centos,redhat はこう
curl https://s3.amazonaws.com/aws-cloudwatch/downloads/latest/awslogs-agent-setup.py -O
sudo python ./awslogs-agent-setup.py --region us-east-1
# Amazon Linux ならこっち
# sudo yum install awslogs

バージョン確認

console
$ /var/awslogs/bin/awslogs-version.sh
略
/etc/cron.d/awslogs_log_rotate version:
# Version: 1.4.3
CloudWatch Logs Plugin Version:
You are using pip version 6.1.1, however version 9.0.1 is available.
You should consider upgrading via the 'pip install --upgrade pip' command.
---
Metadata-Version: 1.1
Name: awscli-cwlogs
Version: 1.4.4
Summary: AWSCLI CloudWatch Logs plugin
Home-page: http://aws.amazon.com/cli/
Author: Amazon
Author-email: UNKNOWN
License: Amazon Software License
Location: /var/awslogs/lib/python2.7/site-packages
Requires: awscli, six, python-dateutil
AWS CLI Version

ログファイル送信設定、先ほどの secure_sshd を指定する

/var/awslogs/etc/awslogs.conf
# 元のmessageログ送信は今回使わないのでコメントアウト
# [/var/log/messages]
# datetime_format = %b %d %H:%M:%S
# file = /var/log/messages
# buffer_duration = 5000
# log_stream_name = {instance_id}
# initial_position = start_of_file
# log_group_name = /var/log/messages

# 普通にsecureログ送るならこう
# [/var/log/secure]
# datetime_format = %b %d %H:%M:%S
# file = /var/log/secure
# buffer_duration = 5000
# log_stream_name = {instance_id}
# initial_position = start_of_file
# log_group_name = /var/log/secure

[/var/log/secure_sshd]
datetime_format = %b %d %H:%M:%S
file = /var/log/secure_sshd
buffer_duration = 5000
log_stream_name = {instance_id}
initial_position = start_of_file
log_group_name = /var/log/secure_sshd

必要に応じてプロキシ設定

/var/awslogs/etc/proxy.conf
HTTP_PROXY=proxyserver:8080
HTTPS_PROXY=proxyserver:8080
NO_PROXY=

サービス再起動&起動設定

console
sudo service awslogs start
sudo chkconfig awslogs on

Logs への送信ログ確認するなら

console
sudo tail /var/log/awslogs.log

動きました

image.png

参考

CloudWatch Logs エージェントのリファレンス – Amazon CloudWatch ログ
クイックスタート: 実行中の EC2 Linux インスタンスに CloudWatch Logs エージェントをインストールして設定する – Amazon CloudWatch ログ
Linux環境設定/sshによる不正アクセスを確認する – Linuxと過ごす
Rsyslog – Wikinote
システム管理の基礎 syslogdの設定をマスターしよう:Linux管理者への道(3) – @IT
必読!ログファイルとディレクトリ | Think IT(シンクイット)

続きを読む

ElasticBeanstalk 上の NodeJS が80番ポートへのアクセスを受けるまでの流れ

Elastic Beanstalk の NodeJS Platform でアプリケーションを作成すると
80 ポートでアクセスできる Web アプリケーションが簡単に出来上がる。

しかし NodeJS は 80 番ポートとは異なるポート 8081 番を Listen しており、
どういった経路で 80 番からのアクセスを受けているのか調べた。

ポート転送の流れ (結論)

  • iptables (PREROUTING)

    • 転送ポート: 80 –> 8080
  • nginx (Proxy)
    • 転送ポート: 8080 –> 8081
  • node (Server)

まず 80 番ポートへのアクセスを iptables が 8080 に変換し、
次に LISTEN 8080 の状態で起動している nginx が 8081 に転送、
次に LISTEN 8081 の状態で起動している NodeJS がリクエストを処理する。

一般的に 0 ~ 1023 番のポートは「well known port」と呼ばれ、Linux では root 権限がないとポートの Listen が出来ない。

root ユーザで nodejs プロセスを動かすことは危険だが、
この構成にすることで nodejs を一般ユーザで起動することが出来る。

ElasticBeanstalk では nodejs プロセスは nodejs ユーザが起動していた。

上記の情報元

EC2 インスタンスに入って上記を調べた時のメモ。
関係のない出力内容は一部割愛。

iptables の設定

80 で受けたアクセスを 8080 へ転送する NAT が作成されている。
PREROUTING チェインのため EC2 インスタンスがアクセスを受けた時にまず処理される。

$ sudo iptables -t nat -S PREROUTING -v
-A PREROUTING -i eth0 -p tcp -m tcp --dport 80 -c 0 0 -j REDIRECT --to-ports 8080

nginx の設定

8080 で受けたアクセスを 8081 に転送するプロキシ設定。
本題とは関係ないが通信の gzip 圧縮・展開もこの層で行われる。

$ cat /etc/nginx/conf.d/00_elastic_beanstalk_proxy.conf
upstream nodejs {
    server 127.0.0.1:8081;
}

server {
    listen 8080;

    location / {
        proxy_pass  http://nodejs;
        proxy_set_header   Connection "";
        proxy_http_version 1.1;
        proxy_set_header        Host            $host;
        proxy_set_header        X-Real-IP       $remote_addr;
        proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

gzip on;
gzip_comp_level 4;
gzip_types text/plain text/css application/json application/javascript application/x-javascript text/xml application/xml application/xml+rss text/javascript;

関連プロセスの Port Listen 状況

node が 8081, nginx が 8080 をそれぞれ Listen していることが分かる。

$ sudo netstat -anp
tcp        0      0 :::8081                     :::*                        LISTEN      2969/node
tcp        0      0 0.0.0.0:8080                0.0.0.0:*                   LISTEN      2977/nginx

NodeJS 起動時の環境変数

PORT=8081 とあるので nodejs は 8081 を Listen する。

$ sudo od -S1 -An /proc/$(ps aux | grep ^nodejs | perl -anlE 'say $F[1]' | tail -1)/environ
PATH=/usr/local/sbin:/usr/local/bin:/usr/bin:/usr/sbin:/sbin:/bin:/opt/elasticbeanstalk/node-install/node-v6.11.5-linux-x64/bin
SHELL=/bin/sh
TERM=linux
EB_NODE_COMMAND=node app.js
USER=nodejs
PWD=/var/app/current
HOME=/tmp
SHLVL=1
UPSTART_INSTANCE=
LOGNAME=nodejs
PORT=8081
UPSTART_JOB=nodejs
NODE_HOME=/opt/elasticbeanstalk/node-install/node-v6.11.5-linux-x64
_=/opt/elasticbeanstalk/node-install/node-v6.11.5-linux-x64/bin/node

NodeJS のデフォルトのアプリケーションソース

上記で分かるように環境変数 PORT が定義されているため、
8081 ポートが Listen される。

app.js
var port = process.env.PORT || 3000,
    http = require('http'),
    fs = require('fs'),
    html = fs.readFileSync('index.html');

var log = function(entry) {
    fs.appendFileSync('/tmp/sample-app.log', new Date().toISOString() + ' - ' + entry + 'n');
};

var server = http.createServer(function (req, res) {
    // 省略
});

続きを読む

t2.microインスタンスでWindowsは使い物になるのか?

ICDP(田舎クラウドデザインパターン)的なネタ再び。

概要

AWS EC2 t2.micro インスタンスのシステム資源は非常に乏しい。
AWS無料利用枠でウィンドウズも対象だけど、本当に使い物になるのか?

目的

t2.microインスタンスへWindows Server 2008R2をインストールしてソフトウェアを起動しようとしたところ、 Out of Memory で起動不能であった。
メモリ1GB、連続して演算できない制限付きのCPU能力で、ウィンドウズを使用するには厳しい。
動作させたいソフトウェアは必要メモリ500MBのため、なんとか使えるようにすることを目的とする。

要件

  • AMI
    Windows_Server-2008-R2_SP1-Japanese-64Bit-Base-2017.11.29 – ami-95d06bf3

  • ページファイル(スワップ)無しで使う。
    スワップが発生したら実用にならないためページファイルは無しとする。
    これはスワップ処理にはCPU時間を消費するため、CPU時間に制限があるt2系インスタンスでは動作が間欠的に停止したり、操作不能に陥ったりするからである。

現状

Windows Server 2008R2 をインストールして起動した状態はこのようになっている。
t2a.jpg

消費メモリは959MB。
メモリ1GBしか無いのに消費メモリがこの状況では無理もない。殆ど空きがない。
40MBではメモリ不足で起動不能となるのは当然であろう。

対処

タスクマネージャでメモリ使用状況を見て削減できそうなプロセスを調べる。
t2b.jpg

TrustedInstaller.exe が460MBも使用している。
これは何かと調べると、Windows Modules Installerサービスのようだ。
Windows Update関連のプログラムで、停止させると更新に失敗するが通常は問題無いので停止させてみた。

無効に設定したサービス

先の大物を含め、無効に設定したサービスは以下の通り。
ただしこれを行うとWindows Updateが失敗するので行う場合は手動で起動し対処すること。

  • Windows Modules Installer
  • Windows Update
  • WinHttp Web proxy Auto-Discovery Service

また、AWSオリジナルの制御機能を使わないのであれば以下も無効にできる。
こちらは計20MB程度の削減にしかならないのでお好みで。

  • Amazon SSM Agent
  • AWS Lite Guest Agent
  • Ec2Config

対処した結果

t2c.JPG

消費メモリが400MB程度となり、600MBの空きを確保できた。

結論

かろうじて要件を満たし動作可能な環境を構築できた。
しかし、リソースには余裕が無いためMackerel等で常時監視した方が良いと思われる。

続きを読む

カップル向けのサービスをメンテフリーで有名なserverless構成で出した話

「Glance(グランス)」 ~カップルのためのYes/No枕アプリ~

2018/01/03より、「Yes/No枕をアプリで」というコンセプトの元に作られたアプリをリリースしましたー!

結構、謎仕様が多くて使い所も不明ですが、
9月ぐらいの「八耐|八時間耐久製作会」というイベントでアイデアから本日のリリースに至りました。

itunes.apple.com_jp_app_glance-yes-no%E3%81%BE%E3%81%8F%E3%82%89_id1294641754_l=ja&ls=1&mt=8.png

https://itunes.apple.com/jp/app/glance-yes-no%E3%81%BE%E3%81%8F%E3%82%89/id1294641754?l=ja&ls=1&mt=8

機能

  • アプリアイコンが動的に変わる、Yes/No枕アプリ

特徴

  • iOS10.3からの機能で、アプリアイコンがYes/Noに動的に変わり、お互いにステータスが見れるというコンセプトです。
  • サーバーサイドはserverless frameworkで
    LambdaとDynamoDBを使っており、メンテコストはほぼ0(ゼロ)

構成

  • アプリ Swift4.0
  • サーバー serverless framework
    • DynamoDB
    • Lambda
    • API Gateway

serverless frameworkとは

  • 「AWS Lambda」と「AWS API Gateway」を利用したサーバレスなアプリケーションを構築するためのツールです。
  • AWSコンソールからだとボタン操作の履歴が残らないですが、serverless frameworkだと全てコードベースで管理できます。

サーバーレスのメリット

  • 管理するサーバーが無いのでサーバーダウンの概念がありません。
  • とにかく安い!
  • 保守メンテが楽でセキュリテイパッチやサーバー管理などのメンテが不要
  • 詳しくはserverlessの魅力を御覧ください

Lambda上でNode.js + Expressがおすすめ

  • API Gatewayでpath管理できますが、serverless + expressのプラグインがあるのでそれに任せたほうが圧倒的に楽になります。

serverless.ymlを晒しとく

  • eventsはanyですべてnodeのExpressに投げます。
serverless.yml
service: yesnoapp

custom:
  defaultStage: dev

provider:
  name: aws
  runtime: nodejs6.10
  profile: yesnoapp
  stage: ${opt:stage, self:custom.defaultStage}
  region: ap-northeast-1
  memorySize: 100
  timeout: 2
  iamRoleStatements:
      - Effect: Allow
        Action:
          - dynamodb:DescribeTable
          - dynamodb:Query
          - dynamodb:Scan
          - dynamodb:GetItem
          - dynamodb:PutItem
          - dynamodb:UpdateItem
          - dynamodb:DeleteItem
        Resource: "arn:aws:dynamodb:${self:provider.region}:*:table/*"

package:
  exclude:
    - .serverless
    - .webpack
    - coverage
    - .babelrc
    - .eslintignore
    - .eslintrc
    - .gitignore
    - LICENSE
    - package.json
    - README.md
    - serverless.yml
    - webpack.config.js


functions:
  app:
    handler: handler.app
    events:
      - http: any {proxy+}

resources:
  Resources:
    YesNoAPPDynamoDbTable:
      Type: 'AWS::DynamoDB::Table'
      DeletionPolicy: Retain
      Properties:
        AttributeDefinitions:
          -
            AttributeName: device_token
            AttributeType: S
        KeySchema:
          -
            AttributeName: device_token
            KeyType: HASH
        ProvisionedThroughput:
          ReadCapacityUnits: 1
          WriteCapacityUnits: 1
        TableName: "Users"

とまあ、こんな感じでExpressが動く!

  • メンテフリー!コストフリー!みんなハッピー!

良かったこと/悪かったこと

ハッカソンのような短期開発には向いている

  • 開発のスタートダッシュが早く、ハッカソンのような短期即本番には向いているといえます。

運用後も安心な価格とコスト

  • ハッカソンで作った作品なので、アクセスはほぼ見込まれません。t2インスタンスなどは、固定でどんどんお金がかかりますが、料金はアクセスが増えた分だけだし、無料枠も十分あるので運用後もずっと残して置けるでしょう。

バズってもなお安心

  • バズることはほぼないですが、もし万が一バズったとしても、サーバーレス設計なら理論上無限スケールで対応することができます。

中盤がきつい

  • スタートダッシュは早いものの、だんだんこだわって作り出すと、Railsだったらこうできるのに…や、DynamoDBだからテーブルわけなくちゃ…NoSQLの苦悩など、中盤のブラッシュアップ期間は忍耐が必要そうです。

まとめ

  • サーバーレス設計は、開発速度が早く安い。とくにハッカソンイベントでは効果を発揮するのでおすすめです!という話でした!

参考

今回参加した八耐の紹介

『八耐』とは

  • 『八耐:八時間耐久作品制作会(仮)』は、8時間でゲームやCG、映像を制作し、参加者全員で発表するイベントです。
  • イベントの最後に発表と試遊会を通じて、新しい繋がりや見知らぬクリエーター同士の交流を深めるイベントにもなっています。
  • 東京と福岡会場があります。私は毎月、東京会場で参加しておりますのでぜひ!
  • http://www.daihachitai.com/index.php/about

続きを読む