エンジニアのはしがき

プログラミングの日々の知見を書き連ねているブログです

Serverless FrameworkならLambda(Node.js)をらくらく作れるよ

ちょっとしたLambda関数を作りたい時は、Node.jsやPythonエンジンのLambdaを作ることが多いのですが、実はいままで自前のシェルスクリプトでzip化した後にLambdaへアップロードしてデプロイしていました。 (今思うとなかなかに面倒な作業でした…)

しかし、設定周りはAWSコンソール上でぽちぽち操作する必要があるので、Roleやレイヤー、タイムアウト設定が大変苦痛になってきたのでServerless Frameworkを導入しました。

続きを読む

RDS Proxyを使いたかったけどNpgsqlから接続できなかった(解決済み)

f:id:tansantktk:20210404183536p:plain

AWSでLambda+RDSの構成を構築すると、Lambda自身が起動の度にRDSへのコネクションを張る為に負荷が大きく、あまり宜しくない構成であると言われてきました。

そのような構成の場合、RDS ProxyをDBプロキシとしてRDSの手前に配置することでコネクションのプーリングが可能になり、RDSへの負荷を抑えることができるようになります。

さて、今回は業務で利用ユーザーが増えてきたこともあり、そろそろ私も導入をしてみようかと検証したところ、どうにもうまくいかなかった話です😂

2021/10/7追記

※無事に接続できました。原因はRDSProxy、RDSのセキュリティグループの設定が間違っており、Lambdaからのリクエストが拒否されていました…。

以下に記載のソースコードは問題ありません。インフラもよく確認しないといけませんね…。

前提条件

  • Lambda(.NET Core 2.1)
  • RDS(PostgreSQL 11)
  • RDS Proxy

上記3つは全て同一VPCに配置。

やりたかったこと

  • LambdaからRDSProxyを経由し、RDSへ接続する。
  • RDSProxyへの接続にはNugetパッケージのNpgsqlを利用。
  • LambdaとRDSProxyの認証については、user, passwordの値の組み合わせを指定して認証する。

ソース

RDS Proxy経由でRDSに接続する場合、Host(NpgsqlではServer)の部分にRDS Proxyのエンドポイントを指定し、後はRDSのUserID, Password, Databaseを指定すれば接続できるという認識でした。

下記は実際に検証したソースコードに似せたサンプルです。

using Npgsql;
using System.Data;

...

var connectionString = @"Server={RDS Proxyのエンドポイント};Port=5432;User Id={UserID};Password={Password}#;Database={Database}";

using (var connection = new NpgsqlConnection(connectionString))
{
  connection.Open();

  var command = new NpgsqlCommand(@"{任意のSQL}", conn);

  var dataReader = command.ExecuteReader();
  while (dataReader.Read())
  {
    // 任意のSQLの実行結果処理
  }
}

結果

  • Lambda環境でNpgsqlを使ってのRDSProxyへの接続は出来ませんでした。
  • NpgsqlでHostをRDSProxyのエンドポイントを指定しましたが、接続が出来ていないようで最終的に.NET Core内でタイムアウトしていました。
  • Lambda(Node.js)からnode-postgresを使ってRDSProxyへ接続を試みたところ、そちらは問題なく接続できました。Npgsqlを使う場合、上記のソースでは接続できないと思われます。

別の接続方法を検討しても良いのですが、Npgsqlを使ったプログラム実装が随所にあり、工数の確保が困難ということで、RDSProxy自体の導入はお流れになりました…。

Lambda+RDS構成なら是非活用したいところだったのですが残念😂

ついにラズパイにもVSCodeがやってきた!

code.visualstudio.com

先日、Raspberry Pi OS(旧Raspbian)でVisual Studio Codeが使えるようになったというアナウンスがありました。

今までずっとラズパイでVSCodeでソース修正ができたらなぁ~と思っていたところだったので、素直に嬉しいです。 早速試してみました!

動作環境

  • Raspbery Pi 3B+
$ lsb_release -a
No LSB modules are available.
Distributor ID: Raspbian
Description:    Raspbian GNU/Linux 10 (buster)
Release:        10
Codename:       buster

なお、当初はRaspbian stretchでapt installしようとしていましたが、パッケージが無いと怒られてしまったのでOSをbusterまでアップデートしたところ、うまくインストールできました。

OSをstretchからbusterにアップデートする場合

www.raspberrypi.org

/etc/apt/sources.list, /etc/apt/sources.list.d/raspi.liststretchという文字列を全てbusterに置き換えて保存します。

$ sudo vim /etc/apt/sources.list
$ sudo vim /etc/apt/sources.list.d/raspi.list

その後、以下のコマンドを実行するとOSのアップデートが開始されます。

$ sudo apt update
$ sudo apt -y dist-upgrade

途中、いくつか選択肢が表示される場合があるので適宜回答をしていきます。 10~20分前後かかったので、ゆとりをもってやっていきましょう。

OSのアップデートが完了したら最後に再起動をします。

$ sudo reboot

VSCodeのインストール

$ sudo apt update
$ sudo apt install code

apt installが完了したら、自動的にスタートメニューの「プログラミング」にVSCodeが追加されます。

f:id:tansantktk:20210403101350p:plain

操作感は今まで通り

f:id:tansantktk:20210403101444p:plain

なんというか安心感があります。 画面構成や操作感は今までのVSCodeと違いは無いようです。 拡張機能やgitの各種機能も通常通り使えます。

ただ、やはりRaspberry Pi 3B+の性能だと動作の遅延やカクつきは避けられないようです。 こればっかりはスペックの問題ですので仕方無いですね。

f:id:tansantktk:20210403102057p:plain

「Help」→「Toggle Developer Tools」を選択すると、Chromeの開発者ツールが表示されました。 今までのVSCode同様、ラズパイのVSCodeもElectron製と思われます。

残念ながら動作しなかったラズパイもあった

ちなみにRaspberry Pi Zero Wでも試してみましたが、apt installは成功するものの、アプリ自体が起動しませんでした。

tm-progapp.hatenablog.com

以前の記事でラズパイのCPUによって、VSCodeのRemote Developmentが未対応のモデルがあることを紹介しましたが、Remote Development未対応のモデルはVSCode自体も使えないのかも。

スペック低めのラズパイは大人しくvimでソースを書くか、外部で書いたソースを送るなりするしかなさそうです。

IAMポリシーAWSLambdaFullAccessは廃止された模様

f:id:tansantktk:20201120002649p:plain

何があったのか

.NET CoreをLambdaへデプロイしようとdotnet lambda deploy-serverlessを叩いたところ、CloudFormationからエラーが返りデプロイできなくなりました。

$ dotnet lambda deploy-serverless --region ap-northeast-1 --stack-name HogeFunction --s3-bucket hoge-bucket

原因

管理者であり、管理ポリシー AWS から非推薦の Lambda へ移行します
2021 年 3 月 1 日を過ぎると、AWS マネージドポリシーである AWSLambdaReadOnlyAccess と AWSLambdaFullAccess は非推奨となり、新しい IAM ユーザーにアタッチできなくなります。ポリシーの非推奨の詳細については、 IAM ユーザーガイド の「 AWS 非推奨の管理ポリシー 」を参照してください。

docs.aws.amazon.com

デプロイ時にIAMポリシーAWSLambdaFullAccessをLambdaにアタッチする設定がserverless.templateに記述されていたのですが、ポリシーが非推奨になった為にアタッチできずにエラーになっていた模様。

互換性を維持する為、非推奨になったポリシーでも既に何らかのUser, Group, Roleにアタッチされている場合、動作自体はするようです。 (ただし、1度ポリシーを外してしまうと二度と再アタッチは出来ないとのこと)

serverless.template

{
  ...
  "Resources" : {
    "AspNetCoreFunction" : {
      "Type" : "AWS::Serverless::Function",
      "Properties": {
        "Handler": "HogeFunction::HogeFunction.LambdaEntryPoint::FunctionHandlerAsync",
        "Runtime": "dotnetcore2.1",
        "CodeUri": "",
        "MemorySize": 256,
        "Timeout": 30,
        "Role": null,
        "Policies": [ "AWSLambdaFullAccess" ],  // 古いポリシーをアタッチしている
        "Environment" : {
          "Variables" : {
            "AppS3Bucket" : { "Fn::If" : ["CreateS3Bucket", {"Ref":"Bucket"}, { "Ref" : "BucketName" } ] }
          }
        },
        "Events": {
          "PutResource": {
            "Type": "Api",
            "Properties": {
              "Path": "/{proxy+}",
              "Method": "ANY"
            }
          }
        }
      }
    },
    "Bucket" : {
        "Type" : "AWS::S3::Bucket",
        "Condition" : "CreateS3Bucket",
        "Properties" : {
            "BucketName" : { "Fn::If" : ["BucketNameGenerated", {"Ref" : "AWS::NoValue" }, { "Ref" : "BucketName" } ] }
        }
    }
  },
  ...
}

対応

AWSLambdaFullAccessの代わりに新しいポリシーAWSLambda_FullAccessが用意されていますので、ポリシー名を差し替えるだけで無事動くようになりました。

ただし、以前のポリシーと比較すると許可するアクション内容が大幅に削減されているので、Lambda関数が動作するかどうか確認した方が良いと思います。 例えばS3へPUTをするような処理をさせるのであれば、別途手動でS3へのアクセスを許可するポリシーをアタッチする必要があります。

AWSLambda_FullAccess

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "cloudformation:DescribeStacks",
                "cloudformation:ListStackResources",
                "cloudwatch:ListMetrics",
                "cloudwatch:GetMetricData",
                "ec2:DescribeSecurityGroups",
                "ec2:DescribeSubnets",
                "ec2:DescribeVpcs",
                "kms:ListAliases",
                "iam:GetPolicy",
                "iam:GetPolicyVersion",
                "iam:GetRole",
                "iam:GetRolePolicy",
                "iam:ListAttachedRolePolicies",
                "iam:ListRolePolicies",
                "iam:ListRoles",
                "lambda:*",
                "logs:DescribeLogGroups",
                "states:DescribeStateMachine",
                "states:ListStateMachines",
                "tag:GetResources",
                "xray:GetTraceSummaries",
                "xray:BatchGetTraces"
            ],
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": "iam:PassRole",
            "Resource": "*",
            "Condition": {
                "StringEquals": {
                    "iam:PassedToService": "lambda.amazonaws.com"
                }
            }
        },
        {
            "Effect": "Allow",
            "Action": [
                "logs:DescribeLogStreams",
                "logs:GetLogEvents",
                "logs:FilterLogEvents"
            ],
            "Resource": "arn:aws:logs:*:*:log-group:/aws/lambda/*"
        }
    ]
}

問題のポリシーは2021/3/1に廃止ということでしたが、3月中頃までは実際のところ正常にデプロイできていました。 実は非公開の猶予期間があったのでしょうか??

.NETライブラリのClosedXMLで既存のExcelファイルを編集する

Excelは好きですか?
僕は嫌いです。規則性に乏しい罫線やセル結合にまみれたエクセルを加工するとかうんざりしますね。 …しかしながら最近既存エクセルのプログラムによる修正を強いられましたのでその方法を記録しておきたいと思います🤮

f:id:tansantktk:20201118205539p:plain

本記事では.NETライブラリのClosedXMLを使ったエクセルの編集方法をまとめています。 NuGetへのインストール手順やエクセルファイルの新規生成については、以前紹介した↓の記事へどうぞ!

tm-progapp.hatenablog.com

続きを読む

Docker上でASP.NET CoreのWebAPIを動かす

f:id:tansantktk:20210314153409p:plain

ASP.NET CoreをDockerで動かしてみたいなーとなんとなく思ったので動かしてみました。 Visial Studioは使わず、VSCodeで動かす想定です。

続きを読む

git bashからdocker runする時にはwinptyを頭につける

f:id:tansantktk:20210314153409p:plain

Dockerを触っていて、ちょっと気づいたことがあったので書き残しておきます。

git bashからDockerコンテナが起動できない?

docker runでDockerイメージからコンテナを生成して起動させる場合、以下のようなコマンドを叩くと思います。

$ docker run --rm --name hoge-app -p 4200:4200 -it hoge-app bash

しかしgit bashをターミナルにした場合は以下の警告メッセージが出力され、実行できません。

the input device is not a TTY.  If you are using mintty, try prefixing the command with 'winpty'

minttyを使っているならコマンドの頭にwinptyを付けろと言われました。

$ winpty docker run --rm --name hoge-app -p 4200:4200 -it hoge-app bash

言われた通りにwinptyを付けるとちゃんと実行されます。

winpty?

git bashはデフォルトだと、minttyというターミナルエミュレータで動作しており、 minttyのおかげでWindows上でもUNIXライクなコマンドが使えるようになっています。

しかし、minttyからpythonipconfig等のWindows上のプログラムを実行した場合、 互換性の問題から正しく実行できない場合が出てくるようです。

winptyはminttyからでもWindows上のプログラムとの入出力を正しく解釈できるように調整をしてくれます。

docker runの場合は警告が出ますので、思考停止でwinptyを頭に付けて差支えはなさそう。

git bashはあくまでgit bashであって、bashではないのね…

Docker Desktop for WindowsでAngularの開発環境をつくる

f:id:tansantktk:20210314153409p:plain

AWS LambdaにDockerコンテナをデプロイできることを知り、Dockerを積極利用するモチベーションが高まってきた今日この頃です。

今回はAngularのDocker上での動かし方を備忘録として残していきたいと思います。

続きを読む

Unicodeの結合文字列がバグを呼び起こしてしまった

f:id:tansantktk:20210313131938p:plain

エクセルに比べれば外部のCSVを扱う処理はまだ悩むことが少ないだろうと油断していたところ、 先日かなり頭を悩ませたので戒めとして記録したいと思います。

続きを読む

AWS CLIバージョン2を使いだしたらlambda invokeが出来なくなった話

f:id:tansantktk:20201120002649p:plain

何をしたかったのか

macOSから下記のようなシェルスクリプトでLambda関数を実行しようとしたのですが、 AWS CLIのバージョンを1から2にアップデートしたところ、突如としてエラーを吐くようになってしまいました。

aws lambda invoke --invocation-type Event \
          --function-name HogeFugaLambdaFunction \
          --region ap-northeast-1 \
          --payload '{ "hoge": "fuga" }' \
          --log-type Tail \
          outputfile.txt

何故動かなかったのか

AWS CLI バージョン 2 はデフォルトで base64 エンコードされた文字列としてバイナリパラメータを渡すようになりました docs.aws.amazon.com

AWS公式からしっかりアナウンスされていました。

今まではLambdaへ渡すjsonは単純に文字列指定していたのですが、base64エンコードが必要になったようです。

修正後

macOSでbase64エンコードする場合はecho '******' | base64を実行します。

aws lambda invoke --invocation-type Event \
          --function-name HogeFugaLambdaFunction \
          --region ap-northeast-1 \
          --payload $(echo '{ "hoge": "fuga" }' | base64) \
          --log-type Tail \
          outputfile.txt

他の手段

~/.aws/config ファイルに追記する

configファイルに追記することで、AWS CLIをバージョン1の挙動に戻すことが可能です。

~/.aws/config

cli_binary_format=raw-in-base64-out

コマンドに追記する

実行するコマンドに下記を付与して、AWS CLIをバージョン1の挙動に戻すこともできるようです。

--cli-binary-format raw-in-base64-out

以外にもググってすぐに答えが探し出せずに悩みました。