20210403のGoに関する記事は3件です。

AWS LambdaとGolangを用いてサーバーレスなビットコイン積立アプリケーションをクラウド上に構築した話

概要 ビットコイン(や他の暗号資産)を定期的に購入するようなアプリケーションを開発しました。暗号資産取引所(bitflyer)のAPIを定期的にコールするようなアプリケーションを開発し、クラウドインフラ(AWS)上で運用を行っています。 ソースコードは以下です。 ↓↓↓ https://github.com/Kohei-Sato-1221/reserve-bitcoin-lambda アプリケーションのアーキテクチャ AWSのクラウドインフラを用いて以下のようなアプリケーションを構築しました。 技術スタック 名称 説明 AWS Lambda サーバーレスアプリケーションを実現。Lambda関数で取引所のAPIをコールします。 Golang Lambda関数はGolangで実装を行いました。 SAM(Serverless Application Model) ローカルでLambdaの開発を行う際に使用。関数の雛形作成・関数のローカルでのエミュレート・関数のデプロイを行います。 Event Bridge Lambda関数を定期的に実行する役割。 System manager(パラメータストア) アプリケーションが使用するパラメータを格納。Lambdaがパラメータを取得します。 アプリ開発の経緯 2021年にビットコインの価格は600万円台に達し、暗号資産は投資の対象として非常に注目度が高まっています。しかし、暗号資産のボラティリティは大きいので、一回の注文で多額の暗号資産を購入してしまうと、大きな含み損が発生してしまう可能があります。 そこで、少額の暗号資産を定期的に購入することで、価格変動のリスクを避けるような購入をしたいと考えました。まさに、ドルコスト平均法の考え方を適応したわけです。 なぜ既存の積立機能を使わないのか? bitflyerやCoinCheckなどでは、ビットコインの積立機能を提供しています。しかし、私はあえてこのようなアプリケーションを実装しました。理由は、価格の点です。既存の積立機能は、基本的に販売所の価格となっており、板取引で購入できる金額よりも手数料が上乗せされています。取引所で暗号資産を取引したほうが安く入手できるのです。 技術的な解説 以下ではアプリケーションをどのような手順で構築したか解説します。 SAM(Serverless Application Model)の導入 SAMとはLambdaのようなサーバーレスアプリケーションの開発する際に役に立つ便利ツールです。これを使えば、Lambda関数の雛形を作成したり、Lambda関数をローカルでエミュレートしたりする(わざわざデプロイしなくても挙動が確認できる)ことができます。 AWS SAM CLIをローカルPCにインストールして、Lambdaの実装を開始しました。 新規注文APIをコールするLambda関数の実装 bitflyerのAPIをコールする機能をLambdaに実装しました。 func (client *APIClient) PlaceOrder(order *Order) (*OrderRes, error) { method := "POST" path := "/v1/me/sendchildorder" url := baseURL + path data, err := json.Marshal(order) if err != nil { return nil, err } header := client.getHeader(method, path, data) res, err := utils.DoHttpRequest(method, url, header, map[string]string{}, data) if err != nil { return nil, err } var orderRes OrderRes err = json.Unmarshal(res, &orderRes) if err != nil { return nil, err } if len(orderRes.ChildOrderAcceptanceId) == 0 { return nil, errors.New(string(res)) } return &orderRes, nil } APIキー・APIシークレットキーの扱い 取引所の注文を行うには取引所のAPIキー・APIシークレットキーが必要になります。Lambda関数にはハードコーディングせずに外部に格納するようにしました。AWSにはSystems Manager パラメータストアという機能があります。このサービスに取引所のAPIキーやAPIシークレットを格納し、アプリケーション実行時にパラメータを取得しています。 apiKey, err := getParameter("buy-btc-apikey") if err != nil { return getErrorResponse(err.Error()), err } apiSecret, err := getParameter("buy-btc-apisecret") if err != nil { return getErrorResponse(err.Error()), err } Event Bridgeによるスケジューリング Event BridgeというサービスではCron式を指定して、Lambdaの起動スケジュールを設定できます。 1日に1回、特定の時間にLambdaが起動するように設定しました。  Udemyで講座を公開しました こちらのアプリケーションの構築方法をUdemyの講座として公開しています。 暗号資産(仮想通貨)の基礎の解説や環境構築のハンズオン・ライブコーディングがまとまった教材となっております。 プロモーションコード欲しい方は、気軽にご連絡ください!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

golangからDockerを操作する

参考 内容 docker psする package main import ( "context" "fmt" "github.com/docker/docker/api/types" "github.com/docker/docker/client" ) func main() { cli, err := client.NewEnvClient() if err != nil { panic(err) } containers, err := cli.ContainerList(context.Background(), types.ContainerListOptions{}) if err != nil { panic(err) } for _, container := range containers { fmt.Printf("%s %s\n", container.ID[:10], container.Image) } } 動作確認 docker run -d nginx:latest yuta@DESKTOP-T85N4KS /t/go-docker> docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES dd9f82fa644e nginx:latest "/docker-entrypoint.…" 26 seconds ago Up 26 seconds 80/tcp compassionate_roentgen yuta@DESKTOP-T85N4KS /t/go-docker> go run main.go dd9f82fa64 nginx:latest
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

WebAPIのログを日付でローテーションする

echoでログを出力するには、公式ドキュメントではmiddleware.Logger()と記載されている。 middleware#Logger main.go package main import ( "net/http" "github.com/labstack/echo/v4" "github.com/labstack/echo/v4/middleware" ) func main() { // Echo instance e := echo.New() // Middleware e.Use(middleware.Logger()) e.Use(middleware.Recover()) // Routes e.GET("/", hello) // Start server e.Logger.Fatal(e.Start(":1323")) } // Handler func hello(c echo.Context) error { return c.String(http.StatusOK, "Hello, World!") } middleware.Logger()でのデフォルトの出力先はos.Stdoutなのでコンソールに出力される。 hoge.go DefaultLoggerConfig = LoggerConfig{ Skipper: DefaultSkipper, Format: `{"time":"${time_rfc3339_nano}","id":"${id}","remote_ip":"${remote_ip}","host":"${host}",` + `"method":"${method}","uri":"${uri}","status":${status},"error":"${error}","latency":${latency},` + `"latency_human":"${latency_human}","bytes_in":${bytes_in},` + `"bytes_out":${bytes_out}}` + "\n", Output: os.Stdout } ファイルに出力するにはos.OpenFile()の戻り値をOutputに指定する。 os.OpenFile()の引数は以下を指定する。 ファイル名・・・日付を含むファイル名を指定する。 操作方法・・・os.O_RDWR|os.O_CREATE(読み書き可能かつ、存在しない場合は新規作成する) パーミッション・・・0664 main.go package main import ( "net/http" "github.com/labstack/echo/v4" "github.com/labstack/echo/v4/middleware" ) func main() { // Echo instance e := echo.New() // Middleware today := time.Now() logfilename := "/log/app-" + today.Format("20060102") + ".log" log, err := os.OpenFile(logfilename, os.O_RDWR|os.O_CREATE, 0664) if err != nil { return e } e.Use(middleware.LoggerWithConfig(middleware.LoggerConfig{ Output: log, })) e.Use(middleware.Recover()) // Routes e.GET("/", hello) // Start server e.Logger.Fatal(e.Start(":1323")) } // Handler func hello(c echo.Context) error { return c.String(http.StatusOK, "Hello, World!") } 簡易的だがechoの起動日単位でログファイルをローテションできる。 サービスを止めないでログをローテーションする方法を次は考えておきたい。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む