HDE BLOG

コードもサーバも、雲の上

Configuring an AWS Lambda Function to Access Both Resources in Public Internet and an Amazon VPC

Hello, this is Bagus from HDE, Inc.

This post is a summary of my presentation on HDE's 21st Monthly Technical Session.

Recently, I’ve been working more with AWS Lambda. There was a time when I created a Lambda function which accesses both resources in public internet and an Amazon VPC. I learned quite a lot from it, so I'd like to share the experience.

続きを読む

第21回 Monthly Technical Session (MTS) 開催!

4/22に毎月行っている Monthly Technical Session (MTS) が開催されました。MTSは、主に技術的な興味関心、また現在行っている取り組みから得られた知見を共有するための取り組みで、今回で第21回目です。

今回は7名のメンバーが発表してくれました。グローバルメンバーが増えてきたこともあって、MTSは司会進行から質疑応答も含めて全編通して英語で行っています。

今回の司会進行はイスカンダルさんでした。

f:id:doi-t:20160422172056j:plain

トップバッターは大久保さん、MkDocsによるドキュメント生成について。ローカルに立てたサーバを使ってリアルタイムにドキュメントが更新される様子をデモで紹介していただきました。

f:id:doi-t:20160422172451j:plain

2人目はバグースさん、AWS lambda functionをVPC内に作った経験を発表していただきました。VPC内のlambda functionからVPC外のAWSリソースにアクセスするにはNAT GatewayやVPC endpointを用意する等、得られた知見を共有してくれました。

f:id:doi-t:20160422174332j:plain

3人目は小河さん、現在開発中のサービスと社内の開発体制について発表してもらいました。各チームメンバーのプロジェクト内における役割、Goを全面的に採用したプロジェクトではコードベースにどれほどインパクトがあるのか、等を社内向けに紹介していただきました。

f:id:doi-t:20160422175453j:plain

休憩を挟んで、4人目は小玉さん、マイクロソフトのActive Directory & Security Conference 2016に参加きた報告をしていただきました。マイクロソフトがAzure ADをどういった形でIDaaSとして提供しようとしているのか、実際にAzureAD認証を行うデモと共に紹介してくれました。

f:id:doi-t:20160422181357j:plain

5人目は4月1日に入社したばかりのジェフリーさん、LXCとは何かについてデモを交えつつ紹介していただきました。発表の中で、LXCのコンセプト、LXDとの関係、またdockerとの違いについて持っている知見を共有してくれました。

f:id:doi-t:20160422182446j:plain

6人目はヘンリーさん、インターンシップ中に開発したツールの紹介をしてくれました。3週間足らずでアイデアを形にして、デモを披露してくれました。

f:id:doi-t:20160422184615j:plain

7人目はグローバルビジネスインターンシップ中のナスタシアさん、出身のウクライナについて、歴史、食べ物、文化などたくさんの写真と共に紹介してくれました。

f:id:doi-t:20160422185502j:plain

この日は、ヘンリーさんの8週間に渡るインターンシップの最終日だったので、MTS終了後に修了式を執り行いました。ちょうど桜のシーズンだったこともあって、インターンシップだけでなく一緒に花見をしたり、夜桜を見に行ったりと、がっつり日本を楽しんでいってくれたように思います。

f:id:doi-t:20160422191600j:plain

当日は弊社CTOが着物で台湾に出張中だったため、ビデオレターにてヘンリーさんへのメッセージを届けてくれました (ビデオのオチで会場の爆笑を掻っ攫っていきました)。

f:id:doi-t:20160422191412j:plain

終わった後は、いつも通りみんなで乾杯!

f:id:doi-t:20160422193339j:plain

第20回 Monthly Technical Sessionが開催されました

3/18に第20回 Monthly Technical Session (MTS) が開催されました。MTSは月一回執り行われる、主に社内向けに現在どのような事を技術者が行っているのかという情報やその中で得られた知見を共有するための取り組みです。

司会のシー・ハンさんが開催をアナウンスしてくれました

f:id:lestrrat:20160318173001j:plain

今回のお題は二つです。最初はイスカンダルさんによる、現在旧アーキテクチャから新アーキテクチャにデータ移行中のサービスの概要についてです。データの整合性の取り方や考えられる問題点等についての説明をしていただきました。

f:id:lestrrat:20160318174551j:plain

次は牧によるJSON Schemaとその関連技術を使ってコードを自動生成するための道のりの話です。サーバーのスケルトン、バリデーション、クライアントコードなどが全てひとつのスキーマから生成されるまでの仮定やなぜ他のツールではなくJSON Schemaを使うのか等の話をしました。

f:id:lestrrat:20160318180115j:plain

トークの後は軽食とビールの時間です!

f:id:lestrrat:20160318190126j:plain

自作Let's EncryptクライアントをGoで書いた話

開発部たなべです。

Let's Encrypt (以下LE)が今年の1月についにDNSベースのドメイン認可をプロダクション環境で有効にしました。

これにより、証明書発行が完全自動化できるのを記念(?)して先月の社内勉強会で少し話しました。つまりは昨年のアドベントカレンダーの続きです。 スライドでも触れましたが、勉強会の当日(1/22)にAWSからACMが発表されるというちょっとしたハプニングがありました。

speakerdeck.com

AAA Updates

AAAとは私が開発しているACMEプロトコルのクライアント実装です。Goで実装しています。

github.com

主な特徴はAWS内で完結させていることです。つまり、

  • すべてのコードはLambda Functionとして実行
  • すべてのデータはサーバサイド暗号化を適用したS3へ保存

することでステートレスでサーバレスを実現しています。アドベントカレンダー以後のアップデートとしては、

  1. 証明書自動更新に対応しました。

    Goで実装したcliアプリをLambda向けにzipし、CloudWatch Eventsを使い、証明書の自動更新処理を行ないます。 Go製のcliをNodeでラップし、Lambda Functionとするのが私の中で王道になりつつあります。OS Xで開発・実行できるうえに、一瞬でLinux向けにビルドできるのでまさにLambda Functionにぴったりです。 早くLambdaのGo対応きてほしいですね。

  2. Slackインテグレーションに対応しました。

    ドメインの認可と証明書の発行がSlackからできます。こちらはAPI Gateway経由でLambda Functionを実行しているだけなので、他とのインテグレーションも難しくないと思います。

  3. ドメイン認可プロセスのDNSチャレンジに対応しました。

    こちらが目玉機能です。Route53環境があれば対象のサーバなしで証明書が発行できます。

今後はApexを利用してLambda Functionを管理できるようにする予定です(ただし、Apex自体ではCloudWatch Eventsには対応せず、Terraformに任せる予定のようです)

Let's EncryptとAmazon Certificate Manager (ACM)

スライドの最後でも触れましたが、改めてLEとACMについて触れます。

ACMはまだ出たばかりでus-eastのみです。現時点ではLEのほうが使い勝手がよさそうです。 リージョンの問題がなくなった場合、ELB連携は魅力的です。AWS内で完結できるのはとてもありがたいです。 また、ACMはワイルドカード証明書にも対応しているので一枚あれば事足りるのも魅力的です。

ACMEプロトコル側でもワイルドカードサポートの議論が始まっています。

github.com

一方で、ACMの証明書発行プロセスではメールでドメインを認可する必要があり、ここが自動化の障害となっています。 でも、証明書の期限は13ヶ月と長いのが幸い、というところでしょうか。

今後ACMEプロトコルの利用が進み、いい感じになったところでACMがACMEプロトコルに対応してくれればすべて丸く収まる…というのが私の妄想です。

ではまた!

Building AWS Lambda function in Rust

This post is a summary of my presentation on 18th Monthly Technical Session.

As I worked more on AWS Lambda for some feature of our service, I looked into developing AWS Lambda functions with languages not supported by Amazon. Recently, I'm working on some private project in Rust so it is worth a try to see whether it is possible to run Rust code on AWS Lambda.

How to run Rust code on AWS Lambda

According to the document of AWS Lambda, the function is run on Amazon Linux with some language runtime and library. It is also possible to spawn new process to run some executable. So there is really little limitation on how the function executes aside from the limitation on CPU, memory and network usage.

There are 2 possible ways to run code in languages not supported:

  • Spawn a new process to run some executable.

    With this way, some standalone executable that is runnable on Amazon Linux is built. The AWS Lambda function creates a new process to run it.

  • Build the code into dynamic load library and load the library with language supported and call the function. (Python or Javascript)

Code written in Rust can be easily compiled into dynamically linked (shared object) library which only depends on GNU libc on a Linux distribution. Also, Python supports loading this kind of library naturally. So the second option is quite adoptable.

Sample project

Here is the code of a sample project to build an AWS Lambda function in Rust with Python code as a loader.

https://github.com/yxd-hde/lambda-rust-demo

The Python loader

To implement handler function in Rust, some code in Python is required to load the library built from Rust and call the function in the library.

Python's cdll package is used to load the library built from Rust (which is named with libhandler.so and uses standard C calling convention) and then the code call the handler function with event and context serialized into json strings.

The code is quite simple and uses simplejson library to do json serialization.

from ctypes import cdll

import simplejson as json

lib = cdll.LoadLibrary('./libhandler.so')


def handler(event, context):
    ret = lib.handle(json.dumps(event),
                     json.dumps(context, default=encode_context))
    return ret


def encode_context(context):
    return {
        "function_name": context.function_name,
        "function_version": context.function_version,
        "invoked_function_arn": context.invoked_function_arn,
        "memory_limit_in_mb": context.memory_limit_in_mb,
        "aws_request_id": context.aws_request_id,
        "log_group_name": context.log_group_name,
        "log_stream_name": context.log_stream_name

        # add others if it is required.
    }

The handler in Rust

In Rust code, the event and context parameters are in C string and need to be converted into Rust strings for further processing. Some unsafe conversion is required to be done before handling them. After that, all things can be done in Rust safely.

Here, Rust's libc library is used for the type of C char pointer, which represents a string in C.

extern crate libc;

use std::ffi::CStr;
use libc::c_char;

#[no_mangle]
pub extern "C" fn handle(c_event: *const c_char,
                         c_context: *const c_char) -> i32 {
    let event = unsafe { CStr::from_ptr(c_event).to_string_lossy()
                         .into_owned() };
    let context = unsafe { CStr::from_ptr(c_context).to_string_lossy()
                           .into_owned() };

    real_handle(event, context)
}

fn real_handle(event: String, context: String) -> i32 {
    println!("Event: {}", event);
    println!("Context: {}", context);

    // Do the real handling

    return 0;
}

Wind them together

To wind them together, there are some extra work to do.

Build the Rust code into an .so file

In Cargo.toml, it is required to tell Rust's build tool cargo that the build target is a dynamic library.

...

[lib]
name = "handler"
crate-type = ["dylib"]

...

Add all the dependencies

The dependencies in Rust are managed by cargo, while requirements.txt is used for Python though there is only simplejson required.

Make the zip package to deploy

Python code, simplejson library and libhandler.so file built from Rust needs to be packaged together in one zip file to deploy.

The libhandler.so file should be binary compatible with Amazon Linux. It is recommended to build it on a distribution that is binary compatible with Amazon Linux.

AWS Lambda settings

An AWS Lambda function with Python environment is required and the handler needs to be set to Python's handler function.

Others

logs

Rust function can just output to stdout for logging as this is supported by AWS Lambda.

error handling

For the code above, the return value of Rust's handler can be used to decide whether the execution succeeded.

Finally

Rust code is safe and supposed to be as performant as C and C++. With this way of implementation, it is possible to use Rust as the language to develop AWS Lambda function easily. It is worth a try if there are requirements to develop performant AWS Lambda function, especially when the function is computation focused.

Developing with Vagrant and Docker

Hi, this is Shi Han from HDE Inc. Before joining HDE Inc. as a software engineer, I was involved in the field of computational physics mainly focusing on computational fluid dynamics and granular materials simulations. The simulations are commonly developed in a monolithic style where the whole simulation is treated/built as a single unit. As for setting up the development environment, usually it only requires the developer to deal the the makefile. As a newcomer in the field of software engineering, I found that things are not quite the same over here. The "recent" trend is that the application can be divided into several small services (microservice architecture) and communicating via HTTP resource API (API-centric architecture). This practice is often applied on applications that are being deployed on the cloud as it allows each services to be deployed and scaled independently.

続きを読む

Tool to help developing AWS Lambda function in Python on your local machine.

We are trying to migrate some part of our service from daemon on EC2 server to serverless function on Lambda. By doing this, we will be able to save some pennies on AWS service and save some time from server maintainence.

At first, we did some development in Javascript on Lambda. And the development went quite well with the awesome tool lambda-local developed by Ahmad Shiina san

ashiina.github.io

With this tool, we are able to develop and debug Javascript code on developer's machine without having to upload it to the cloud. With a shortened develop-deploy-test-fix cycle, we managed to develop features really fast.

We were just about to go all with Javascript when AWS enabled developing Lambda functions in Python2.7 at re:Invent 2015.

Using Python in an AWS Lambda Function | AWS Compute Blog

Since part of our stack is based on Python2 and most of our developers are more familiar with Python than Javascript. We decided to give it a try.

However, one problem is that there is no tool like lambda-local for Python right now. So we built one by ourselves and opensourced it on github.

github.com

We have also released it on PyPI

pypi.python.org

So you may try it our by installing it into a Python2.7 environment with just one command:

$ pip install python-lambda-local

Currently, it is quite feature complete except lacking enough support for the Context API. We will continue improving it.

The usage of the python-lambda-local command is quite similar with lambda-local. So there should be no hassle if you are familiar with lambda-local.

Ideas and pull requests are welcomed.

Happy hacking!