プラグ可能なGolangアプリケーションを構築し、AWS Lambda Layersを活用する方法。

Golang —なぜ注目に値するのですか?

Golangは、Googleが設計および実装したオープンソースのプログラミング言語です。最近のアプリケーション、特にクラウドで非常に広く使用されています。最も特徴的な機能は次のとおりです。

  • Golangは静的に型指定されています-柔軟性は低くなりますが、ミスを防ぎます。
  • オブジェクト指向ではありません。ただし、構造とインターフェイスを作成することができます。これにより、4つのOOP原則のうち3つ(データの抽象化、カプセル化、ポリモーフィズム)が得られます。継承は唯一の欠落であり、
  • ゴルーチン! —私がこれまで使用してきたライトスレッドの最大の実装。 go演算子を使用して非常に簡単な方法で新しいスレッドを作成し、チャネルを使用して異なるゴルーチン間で通信できます。
  • すべての依存関係を持つ単一のバイナリにコンパイルされます。パッケージの競合はもうありません!

個人的には、私はGolangを日常的に使用する最大の言語だと考えています。ただし、この記事では、最初の関数の作成や「Hello World」の印刷については説明しません。もう少し高度なものを紹介します。あなたが初心者で、Golangについてもっと知りたい場合は、メインページにアクセスしてください。

AWS LambdaとGolang

AWS Lambdaは、パブリッククラウドで最も人気のあるサーバーレスコンピューティングサービスの1つであり、2014年11月にAmazon Web Servicesによってリリースされました。サーバーをプロビジョニングまたは管理せずに、DynamoDB、SNS、HTTPトリガーなどのイベントに応じてコードを実行できます!何が本当に素晴らしいか知っていますか? 2018年1月以降、Golangランタイムをサポートしています。 AWS Lambdaの操作は非常に簡単です。コードとすべての依存関係(Golangを使用する場合はシングルバイナリ)を圧縮したパッケージをアップロードするだけです。

4年後の2018年re:Invent AWSは、1つまたは複数のAWSアカウントのさまざまな機能で共有されるデータを保存および管理できるLambdaレイヤーをリリースします!たとえば、Pythonの使用中に、他のLambdaが後で使用できる追加のレイヤーにすべての依存関係を配置できます。圧縮されたパッケージごとに異なる依存関係を配置する必要はもうありません! Golangの世界では、AWS Lambdaではコンパイル済みのバイナリをアップロードする必要があるため、状況は異なります。 AWS Lambdaレイヤーからどのように利益を得ることができますか?答えは簡単です-Golangプラグインを使用してモジュラーアプリケーションを構築してください!

Golangプラグイン—モジュラーアプリケーションを構築する方法

GolangプラグインはGo1.8でリリースされた機能で、共有ライブラリ(.soファイル)を動的にロードできます。これにより、コードの一部を別のライブラリにエクスポートしたり、誰かが準備してコンパイルしたプラグインを使用したりできます。有望ですが、いくつかの制限があります。

  • プラグインは単一のメインモジュールである必要があり、
  • ロードできるのは、ELFシンボルとしてエクスポートされた関数と変数のみです。
  • 静的型付けのため、ロードされたすべてのシンボルを正しい型にキャストする必要があります。最悪のシナリオでは、コードで正しいインターフェイスを定義する必要があります。
  • LinuxおよびMacOSでのみ機能します。個人的に、私はこれを欠点とは考えていません:)

最初のプラグインの構築とテスト

では、最初のプラグインを作成しましょう。例として、文字列暗号化用の簡単なモジュールを作成します。基本に戻って、CeasarとVermanの2つの単純な暗号化アルゴリズムを実装しましょう。

  • シーザー暗号は、Julius Ceasesが最初に使用したアルゴリズムです。テキスト内のすべての文字を固定の位置数だけシフトします。たとえば、golangという単語をキー4で暗号化する場合、ktpekを取得します。復号化も同様に機能します。あなたはちょうど反対方向に文字をシフトする必要があります。
  • バーマン暗号はシーザーに似ていますが、同じシフトの考え方に基づいていますが、違いは、すべての文字を異なる位置数だけシフトすることです。テキストを復号化するには、テキストの暗号化に使用される位置を含むキーが必要です。たとえば、キー[-1、4、7、20、4、-2]を使用してgolangを暗号化する場合は、将来取得します。

この例の完全な実装はこちらから入手できます。

プラグインの実装

次のスニペットには、上記の2つのアルゴリズムの実装が含まれています。それぞれについて、テキストを暗号化および復号化する2つの方法を実装します。

ご覧のとおり、ここで3つの異なるシンボルをエクスポートしました(Golangは、大文字で始まるこれらの識別子のみをエクスポートします)。

  • EncryptCeasar-Ceasarアルゴリズムを使用してテキストを暗号化するfunc(int、string)文字列、
  • DecryptCeaser-Caeserアルゴリズムを使用してテキストを復号化するfunc(int、string)文字列、
  • VermanCipher-2つのメソッドを実装するvermanCipher型の変数:Encrypt:func(string)string and Decrypt:func()(* string、error)

このプラグインをコンパイルするには、次のコマンドを実行する必要があります。

ビルドする-buildmode = plugin -o plugin / cipher.so plugin / cipher.go

今のところ、特別なことは何もありません-いくつかの単純な関数が作成され、モジュールは-buildmode = plugin引数を追加することでプラグインとしてコンパイルされました。

プラグインのロードとテスト

コンパイルされたプラグインをアプリで使用したいときに楽しみが始まります。簡単な例を作成しましょう:

まず、golangプラグインパッケージをインポートする必要があります。 2つの関数のみが含まれています-最初の関数は共有ライブラリをロードするためのもので、2番目の関数はエクスポートされたシンボルを見つけるためのものです。ライブラリをロードするには、共有プラグインへのパスを提供する必要があり、プラグインタイプの変数を返すOpen関数を使用する必要があります。ライブラリのロードが不可能な場合(例:不正なパスまたは破損したファイル)、この関数は処理する必要のあるエラーを返します。

次のステップは、ルックアップメソッドを使用して、エクスポートされたすべてのシンボルをロードすることです。少し不便ですが、エクスポートされたすべての関数を個別に読み込む必要があります。ただし、VermanCipherシンボルの場合と同じ方法で、複数の関数を組み合わせることができます。使用するすべてのシンボルをロードしたら、それらを正しいタイプにキャストする必要があります。 Golangは静的に型付けされた言語であるため、キャストせずにこれらのシンボルを使用する他の方法はありません。いくつかのメソッドを実装する変数をエクスポートするときは、正しいインターフェイスタイプにキャストする必要があります(これを処理するにはencryptionEngineインターフェイスを定義する必要がありました)。\ newline \ newline

アプリをコンパイルして実行するには、次のコマンドを使用します。

app.goをビルドします
./app

出力では、アルゴリズムが正しく機能することの証明として、暗号化および復号化されたテキストが表示されます。

AWSラムダでプラグインを使用する

AWS Lambdaでプラグインを使用するには、アプリケーションにいくつかの変更を加える必要があります。

  • AWS Lambdaは、ラムダコンテナの/ optディレクトリにレイヤーをマウントするため、このディレクトリからプラグインをロードする必要があります。
  • テストイベントを処理するためにLambdaエンジンで使用されるハンドラー関数を作成する必要があります。

次のスニペットには、Lambdaで使用するように調整されたアプリケーションが含まれています。

ご覧のとおり、実装は前のものと非常に似ています。プラグインをロードしたディレクトリを変更し、値を出力する代わりに関数応答を追加しただけです。 golangでのLambdaの作成について詳しく知りたい場合は、AWSのドキュメントをご覧ください。

AWS Lambdaのデプロイ

AWS Lambda関数とレイヤーをデプロイするには2つの方法があります。 zip形式のパッケージを手動で作成してアップロードするか、より高度なフレームワークを使用すると、はるかに簡単かつ高速になります。私のほとんどのプロジェクトでは、サーバーレスフレームワークを使用しているため、このツールを使用して簡単なserverless.yml構成ファイルを既に準備しています。

サービス:cipherService
frameworkVersion: "> = 1.28.0 <2.0.0"
プロバイダー:
  名前:aws
  ランタイム:go1.x
レイヤー:
  cipherLayer:
    パス:bin / plugin
    互換性のあるランタイム:
      -go1.x
関数:
  エンジン:
    ハンドラー:bin / cipherEngine
    パッケージ:
      除外:
        -./**
      含める:
        -./bin/cipherEngine
    レイヤー:
      -{参照:CipherLayerLambdaLayer}

レイヤーセクションでは、作成済みのプラグインへのパスを持つ単一のレイヤーを定義しました-ラムダ関数と一緒にデプロイされます。順序が本当に重要な最大5つの異なるレイヤーを定義できます。それらは同じ/ optディレクトリにマウントされるため、より高い番号のレイヤーは、以前にマウントされたレイヤーのファイルをオーバーライドできます。レイヤーごとに、少なくとも2つのパラメーターを指定する必要があります。レイヤーソースを含むディレクトリへのパス(この場合はプラグインバイナリへのパス)と互換性のあるランタイムのリストです。

次の機能セクションは、デプロイする機能のリストを定義する場所です。すべての関数について、少なくともコンパイル済みアプリケーションへのパスを提供する必要があります。さらに、上記で定義されたレイヤーへの参照を使用して、layersパラメーターを定義する必要があります。これにより、デプロイ中にレイヤーがLambda関数に自動的にアタッチされます。面白いことに、ラムダレイヤー名をTitleCasedに変換し、そのリソースを参照する場合はLambdaLayerサフィックスを追加する必要があります。サーバーレスチームは、さまざまな種類のリソースを参照して競合を解決するために、この方法で実装したようです。

serverless.yml設定ファイルの準備ができたら、最後に行うことは、アプリをコンパイルし、プラグインし、デプロイすることです。そのために簡単なMakefileを使用できます。

.PHONY:build buildPlugin clean deploy
ビルド:
 dep ensure -v
 env GOOS = linux go build -ldflags = "-s -w" -o bin / cipherEngine cipherEngine / main.go
buildPlugin:
 env GOOS = linux go build -ldflags = "-s -w" -buildmode = plugin -o bin / plugin / cipher.so ../plugin/cipher.go
クリーン:
 rm -rf ./bin ./vendor Gopkg.lock
deploy:clean buildPlugin build
 sls deploy --verbose

次のコマンドを実行して、関数をビルドおよびデプロイできます。

展開させる

AWS Lambdaをテストする

前述したように、AWS Lambdaはイベントへの応答でコードを実行します。ただし、イベントトリガーは設定しなかったため、サポートなしで呼び出すことはできません。サーバーレスフレームワークまたはawscliツールを使用して手動で行う必要があります。

sls invoke -f function_name
aws lambda invoke —関数名function_name output_file

応答では、以前と同じ出力が表示されるはずです。これは、ラムダ関数が正しく機能し、追加レイヤーからプラグインをロードすることを証明しています。同じレイヤーを使用する他の関数を作成したり、他のAWSアカウントと共有することもできます。

概要

Golangモジュールを使用して、新しくリリースされたAWS Lambdaレイヤーと統合する方法をテストするのはとても楽しかったです。プラグインライブラリは本当に素晴らしいですが、その制限とGolang仕様のために、いくつかの特別なシナリオでのみ使用できます。標準プロジェクトに取り組んでいるほとんどの開発者にとって、プラグインを使用する必要はないか、使用することさえできないと思います。 2つの理由だけが思い浮かびます。

  • 他のアプリケーションで使用できる複雑なアルゴリズムの実装。ビデオコーディングまたは暗号化アルゴリズム。
  • コードを公開せずにアルゴリズムを他の人と共有する。