ようへいの日々精進XP

よかろうもん

2020 年 07 月 13 日 (月)

アクティビティ (今までの走行 (歩行) 距離)

https://pixe.la/v1/users/inokappa/graphs/fitbit-activity

Fitibit Charge2 のアクティビティから走行 (歩行) 距離を Fitbit Web API で取得して Pixela で草生やしている. 色が濃くなれば濃くなる程強度が高い (歩行, 走行距離が長い) ということで. 実装の詳細はこちら.

ジョギング

仕事が終わってから走った.

走り終わってから軽い目眩がして焦った.

ギョーム

  • CircleCI Orbs について調べた (特に Code Sharing Terms について)
  • ECS AMI update
  • 古い AWS リソース (AMI とそれに関連付いているスナップショット) の削除等

ディナー

豚バラと茄子の甘辛おろし, 桜えびがたっぷりのった生姜ご飯がとても美味しゅうございました.

ecs-deploy をインストールする CircleCI orbs を作ってリリースしました

tl;dr

ECS クラスタのタスク定義を作成して ECS サービスを更新する (ECS にアプリケーションをデプロイする) ecs-deploy というシェルスクリプトで実装されたツールをインストールする CircleCI orbs を作ってリリースしたのでメモしておきます.

CircleCI orbs とは

すごくざっくり言うと, CircleCI のワークフローで実行する各種ジョブをまとめて再利用出来るようにしたものです.

circleci.com

.circleci/config.yml には以下のように指定することで利用です.

---
version: 2.1

orbs:
  aws-cli: circleci/aws-cli@1.2.1
  ecs-deploy: inokappa/ecs-deploy-install@dev:0.0.3

jobs:
  integration:
    docker:
      - image: cimg/base:2020.01
    steps:
      - aws-cli/install
      - ecs-deploy/install:
          latest: true
      - run:
          name: Get ecs-deploy version
          command: |
            ecs-deploy --version

workflows:
  integration_test:
     jobs:
       - integration

但し, デフォルトではサードパーティ製の orbs は利用出来ない設定になっている (?) ようなので, 設定で有効にしてあげる必要があります.

f:id:inokara:20200712231536p:plain

作ったもの

github.com

以下のように利用されることを想定しています.

---
version: 2.1

orbs:
  aws-cli: circleci/aws-cli@x.y
  ecs-deploy: inokappa/ecs-deploy-install@x.y

jobs:
  build:
    docker:
      - image: cimg/base:2020.01
    steps:
      - aws-cli/install
      - ecs-deploy/install:
          latest: true
        - run:
            command: |
              ecs-deploy --cluster your-ecs-cluster \
                --image your-container-image \
                --service-name your-ecs-service-name \
                --region ap-northeast-1 \
                --timeout 300 \
                --enable-rollback

latest:true を付与することで, 常に最新の ecs-deploy がインストールされます. また, version: x.x.x を指定することで任意のバージョンを指定することが出来ますが, わざわざ古いバージョンを指定して利用することはあまりないと思いますので, 基本的には latest:true で良いと思います.

この orbs がもたらしたメリット

従来は, .circleci/config.yml 内に以下のように ecs-deploy をインストールする各種コマンドを記述していました.

version: 2.1
...
commands:
  setup_ecs_deploy:
    steps:
      - run:
          name: Setup ecs-deploy
          command: |
            latest=$(curl -s 'https://api.github.com/repos/silinternational/ecs-deploy/tags' | jq -r '.[].name' | head -1 || true)
            curl -s https://raw.githubusercontent.com/silinternational/ecs-deploy/${latest}/ecs-deploy | tee -a /usr/local/bin/ecs-deploy \
              && chmod +x /usr/local/bin/ecs-deploy

jobs:
  deploy:
    executor: default
    steps:
      - checkout
      - setup_remote_docker:
          docker_layer_caching: true
...
      - setup_ecs_deploy 
...

これを orbs に変更することで, 以下のように commands.setup_ecs_deploy が丸っと無くなっているので, .circleci/config.yml が少しだけシンプルになりました.

version: 2.1
...
orbs:
  ecs-deploy: inokappa/ecs-deploy-install@0.0.1

jobs:
  deploy:
    executor: default
    steps:
      - checkout
      - setup_remote_docker:
          docker_layer_caching: true
...
      - ecs-deploy/install
...

実装

とてもシンプルなシェルスクリプト

YAML の中に複数行のシェルスクリプトを書くのに違和感を感じつつも, この orbs のコアとなるのが src/commands/install.yml となります. 以下, 抜粋です.

---
description: |
  Installing ecs-deploy.

parameters:
  version:
    description: ecs-deploy version.
    type: string
    default: ""
  latest:
    description: install latest version.
    type: boolean
    default: true
...
  - run:
      name: "Install ecs-deploy"
      command: |
        set +e
        VERSION=<<parameters.version>>
        if [ "${VERSION}" == "" ]; then
          VERSION=$(curl -s 'https://api.github.com/repos/silinternational/ecs-deploy/tags' | jq -r '.[].name' | head -1 || true)
        fi

        if [ -z "${VERSION}" ];then
          echo "Please specify 'version'."
          exit 1
        fi

        curl -s https://raw.githubusercontent.com/silinternational/ecs-deploy/${VERSION}/ecs-deploy | sudo tee -a /usr/local/bin/ecs-deploy \
          && sudo chmod +x /usr/local/bin/ecs-deploy
...

<<parameters.xxxx>> で orbs に指定するパラメータを取得することが出来ます.

orbs ソースコードを分割する

orbs は一枚の YAML で記述することが出来ますが, 以下のようなディレクトリ構成で分割して実装することが出来るようです.

$ tree src
src
├── @orb.yml
├── commands
│   └── install.yml
└── examples
    └── example.yml

2 directories, 3 files

分割することで, circleci/orb-tools という orbs のテストやデプロイまで一気通貫で行える, これまた orbs のワークフローに載せやすくなるとのことで, それにならってみました. 尚, 分割した YAML ファイルは, circleci コマンドを利用して結合することが出来ます.

$ circleci config pack --skip-update-check src > orb.yml

テスト

先述の circleci/orb-tools を使えば, 簡単に orbs の動作確認を行うことが出来ました. 以下は本 orbs 自体の .circleci/config.yml です.

---
version: 2.1

orbs:
  orb-tools: circleci/orb-tools@9.1.1

workflows:
  lint_pack_test_publish-dev:
    jobs:
      - orb-tools/lint
      - orb-tools/pack:
          requires:
            - orb-tools/lint
      - orb-tools/test-in-builds:
          name: test-latest-version
          attach-workspace: true
          orb-name: ecs-deploy
          test-steps:
            - orb-tools/local-test-build:
                test-config-location: test/latest.yml
          requires:
            - orb-tools/pack
      - orb-tools/publish-dev:
          name: test-specify-version
          attach-workspace: true
          orb-name: ecs-deploy
          test-steps:
            - orb-tools/local-test-build:
                test-config-location: test/version.yml
          requires:
            - test-latest-version
      - orb-tools/publish-dev:
          orb-name: inokappa/ecs-deploy-install
          requires:
            - test-specify-version

orb-tools/test-in-builds を利用することで, circleci local execute を実行して実際に orbs を使った動作確認を走らせることが出来ます. 以下は実際の実行されたジョブです.

circleci.com

参考にさせて頂いた記事では, バージョン番号を指定して orbs Registry に Publish するところまでを orb-tools に任せていてよく出来た orbs だなーと感激した次第です. 尚, 本 orbs ではテストまでで Publish 自体は手動でやっています. すいません. これは追々対応したいと思います.

以上

実は, この orbs を作ったきっかけとなったプロジェクトでは, サードパーティ製 orbs が利用出来ない設定になっていて切なくなってしまいましたが, orbs について色々と学ぶことが出来て良かったです.

参考

以下の記事を参考にさせて頂きました. ありがとうございました.

circleci.com

github.com

masutaka.net

2020 年 07 月 12 日 (日)

アクティビティ (今までの走行 (歩行) 距離)

https://pixe.la/v1/users/inokappa/graphs/fitbit-activity

Fitibit Charge2 のアクティビティから走行 (歩行) 距離を Fitbit Web API で取得して Pixela で草生やしている. 色が濃くなれば濃くなる程強度が高い (歩行, 走行距離が長い) ということで. 実装の詳細はこちら.

ジョギング

午後から走った.

ギョーム

  • お休み
  • ecs-deploy をインストールするだけの CircleCI orbs をリリースした

github.com

orbs そのものはシェルスクリプトで実装するので解りやすいものの, orbs 自体の CI/CD 設定に時間を要した気がする.

ディナー

長芋をスライスして明太子や納豆をトッピングした, 「オンザ長芋」とタラのフライ. 「オンザ長芋」も「タラのフライ」も我が家の定番メニューに入れたいくらい美味しゅうございました.

2020 年 07 月 11 日 (土)

アクティビティ (今までの走行 (歩行) 距離)

https://pixe.la/v1/users/inokappa/graphs/fitbit-activity

Fitibit Charge2 のアクティビティから走行 (歩行) 距離を Fitbit Web API で取得して Pixela で草生やしている. 色が濃くなれば濃くなる程強度が高い (歩行, 走行距離が長い) ということで. 実装の詳細はこちら.

ジョギング

今朝はアクトネルを飲んだので, しばらく安静にした後, 12 時くらいから山王公園を走った.

ギョーム

  • お休み

ThinkPad TrackPoint II キーボード

inokara.hateblo.jp

ディナー

がっつりお肉を食べたくて, ルミエールで 500 円くらいの輸入肉を買ってきてフライパンで雑に焼いて食べた. 我ながら美味しゅうございました. あと, 奥さんが作った「タコとニラのピリ辛和え」は安定の美味しさで我が家の定番に認定.

ThinkPad TrackPoint II キーボード (英字配列) を導入した

tl;dr

初代を使っていて, 二代目がとても良いという記事を読んだので Lenovo ストアで発売が開始された直後に発注, 今日, やっとこせっとこ手元に届いたのでメモしておく.

お小遣いが少なくてパソコンは買えないのでキーボードだけ買いました。待ちに待った ThinkPad TrackPoint Keyboard II です。

ThinkPad TrackPoint II キーボード

www.lenovo.com

以下は, ThinkPad TrackPoint II キーボードを称賛する記事のいくつか.

japanese.engadget.com

www.itmedia.co.jp

www.gizmodo.jp

TrackPoint II キーボードの基本的なスペック等については, 上記の記事や以下の公式ドキュメントに書かれているので割愛.

support.lenovo.com

各種言語のマニュアル (ユーザーズガイド) へのリンクも掲載されている.

macOS で使う

手元の macOS の情報は以下の通り.

ProductName:    Mac OS X
ProductVersion: 10.15.5
BuildVersion:   19F101

TrackPoint II キーボードは WindowsAndroid のみサポートされていて, macOS はサポート外なので注意が必要だが, 以下の手順でペアリングを行ったところすぐに繋がって利用することが出来た.

f:id:inokara:20200711192457j:plain ユーザーズガイド より引用.

TrackPoint II キーボードには USB ドングル (2.4GHz USB レシーバー) も付属しており, このレシーバーを接続することで, 同時に最大 2 台の端末を切り替えて利用することが出来る. もう一台も macOS 端末で試してみようかなと思う.

macOS で使う上でのカスタマイズ

ペアリングしただけだと, 個人的に使い辛かったので, 日本語変換の ON/OFF や Control キーを A キーの隣に配置するように設定した.

上記以外は現時点ではカスタマイズしていない.

気付いたこと等

初代よりも

少し重くなったのかな. 重厚感が増した感じで高級感が出たような気がする.

キータッチ

初代と比較してキータッチが良くなった旨の記事をチラホラ見ていたのでとても期待していたところもあったけど, 量販店で ThinkPad X1 Carbon を触った時に指に吸い付くような感覚が忘れられなくて, それと同じような感覚を期待していただけにちょっと残念.

TrackPoint の真ん中ボタンがうざい

TrackPoint は左右クリック用と真ん中にもボタンがあるけど, このボタンを使ってブラウザ等でスクロールしていると, うっかりリンクをクリックして新しいタブが開いたりすることがちょくちょく. これ, なんとかならんのかな...

以上

ThinkPad TrackPoint II キーボードを導入したメモでした. もちろん, この記事も TrackPoint II キーボード で書きました. そして, やっぱり, ThinkPad (ノートパソコンの方) が欲しくなったので貯金をしたいと思います.

docker コマンドで ECS クラスタにデプロイ出来るようになった (beta 版) ので試してみたけど挫折した

tl;dr

AWS より以下のようなブログがポストされました.

aws.amazon.com

合わせて, Docker でも同じようなブログがポストされていました.

www.docker.com

英語は読めませんが, ざっくりと読んだ限りだと docker-compose.yml があれば, docker に ecs コマンドが追加されて, 以下のように, docker-compose up する感覚で, ローカル PC からダイレクトに ECS にアプリケーションが出来るようになったようなので, 試してみました.

$ docker ecs compose up

尚, この機能は現時点では, Public Beta 版として公開されており, 先述のブログ記事でも Edge バージョンの Docker for Mac を利用して確認が可能ということですので, Edge バージョンを利用して動作確認しています. そのため, 開発の状況によって, 記事の内容とは異なる結果が得られることがあるかと思いますのでご注意下さい. また, 記事内に誤りや言葉の誤用等もあるかもしれませんので合わせてご留意下さい.

以下, 動作確認環境の情報です.

$ sw_vers
ProductName:    Mac OS X
ProductVersion: 10.15.5
BuildVersion:   19F101

$ docker version
Client: Docker Engine - Community
 Azure integration  0.1.7
 Version:           19.03.12
 API version:       1.40
 Go version:        go1.13.10
 Git commit:        48a66213fe
 Built:             Mon Jun 22 15:41:33 2020
 OS/Arch:           darwin/amd64
 Experimental:      true

Server: Docker Engine - Community
 Engine:
  Version:          19.03.12
  API version:      1.40 (minimum version 1.12)
  Go version:       go1.13.10
  Git commit:       48a66213fe
  Built:            Mon Jun 22 15:49:27 2020
  OS/Arch:          linux/amd64
  Experimental:     true
 containerd:
  Version:          v1.2.13
  GitCommit:        7ad184331fa3e55e52b890ea95e65ba581ae3429
 runc:
  Version:          1.0.0-rc10
  GitCommit:        dc9208a3303feef5b3839f4323d9beb36df0a9dd
 docker-init:
  Version:          0.18.0
  GitCommit:        fec3683

以下, Docker for Mac の情報です.

f:id:inokara:20200711063859j:plain

チュートリアル

要件

この機能 (以後, 「ECS 連携機能」と書きます) を利用するには, 現時点では Docker for Mac の Edge バージョンが必要になります. また, IAM ユーザー又は IAM Role に以下の権限を付与する必要があるようです.

  • ec2:DescribeSubnets
  • ec2:DescribeVpcs
  • iam:CreateServiceLinkedRole
  • iam:AttachRolePolicy
  • cloudformation:*
  • ecs:*
  • logs:*
  • servicediscovery:*
  • elasticloadbalancing:*

ecs-plugin

ECS 連携機能は, Docker CLIプラグイン ecs-plugin として提供されているようです.

github.com

このリポジトリの example フォルダにサンプルアプリケーションが収められているので, 本記事の中でも利用させて頂きたいと思います. また, example フォルダ内の README に則ってチュートリルを進めます.

尚, example フォルダ内 docker-compose.yml は以下のように書き換えています.

version: "3.8"
services:
  frontend:
    build: app
    # x-aws-pull_credentials: <<<your arn for your secret you can get with docker ecs secret list>>>
    image: ${DOCER_HUB_ACCOUNT}/timestamper
    ports:
      - "5000:5000"
    depends_on:
      - backend
  backend:
    image: redis:alpine

また, Docker Hub にログインしておく必要があります.

$ docker login

尚, ecs-plugin は以下の通り確認出来ます.

$ docker help | grep ecs
  ecs*        Docker ECS (Docker Inc., v1.0.0-beta.1)

$ docker ecs version
Docker ECS plugin v1.0.0-beta.1 (12a47cb)

docker ecs setup

ECS 連携機能を利用する為には, docker ecs setup コマンドを使ってコンテキストを作成する必要があります.

f:id:inokara:20200711065016j:plain

コンテキストを作成後, docker context ls を実行して確認してみます.

$ docker context ls
NAME                TYPE                DESCRIPTION                               DOCKER ENDPOINT               KUBERNETES ENDPOINT              ORCHESTRATOR
aws                 aws
default *           moby                Current DOCKER_HOST based configuration   unix:///var/run/docker.sock   https://xxx.xxx.xxx.xxx (default)   swarm

コンテナイメージを Docker Hub にプッシュ

サンプルアプリケーションを一旦, ローカル PC でビルドした後 (docker-compose build), 以下を実行して Docker Hub にサンプルアプリケーションイメージをプッシュします.

$ docker-compose push

コンテキストを切り替える

先述の docker ecs setup で作成した ECS 連携機能用コンテキストに切り替えます.

$ docker context use aws

以下のように出力されます.

$ docker context use aws
aws

ちょっとさみしい出力ですね.

docker ecs compose up

早速, サンプルアプリケーションを起動してみたいと思います.

$ docker ecs compose up

以下のように出力されました.

$ docker ecs compose up
WARN[0000] services.build: unsupported attribute
account has not default VPC

oh... Default VPC が必要になるようです... 万事休すでした. ecs-plugin の実装を見ると, 現時点では, 以下のようにデフォルト VPC のみをサポートするようになっていました.

...
func (s sdk) GetDefaultVPC(ctx context.Context) (string, error) {
    logrus.Debug("Retrieve default VPC")
    vpcs, err := s.EC2.DescribeVpcsWithContext(ctx, &ec2.DescribeVpcsInput{
        Filters: []*ec2.Filter{
            {
                Name:   aws.String("isDefault"),
                Values: []*string{aws.String("true")},
            },
        },
    })
    if err != nil {
        return "", err
    }
    if len(vpcs.Vpcs) == 0 {
        return "", fmt.Errorf("account has not default VPC")
    }
    return *vpcs.Vpcs[0].VpcId, nil
}
...

検証で利用している AWS アカウントには Default VPC が存在しておらず, しかも, 以下のように新たにデフォルト VPC を作ることが出来なかった為, 動作確認はここで断念することにしました. (新しい AWS アカウントを作る気力が無かった...)

$ aws ec2 create-default-vpc

An error occurred (OperationNotPermitted) when calling the CreateDefaultVpc operation: Accounts on the EC2-Classic platform cannot create a default VPC.

雑にコードリーディング

残念ながら

手元の環境では動作を確認することが出来なかったので, ecs-plugin のソースコードをざっくりと読んでみました.

docker ecs compose

docker ecs compose には以下のようなサブコマンドが用意されています.

  • convert
  • up
  • down
  • logs
  • ps

これらは, ここの部分で定義しています. それぞれの機能について, コアな実装は, pkg/amazon/backend 以下にそれぞれ実装されています.

f:id:inokara:20200711092610j:plain

この中から up.go について見てみます.

up.go

up.go はその名の通り, docker ecs compose up を実行した際に呼ばれる関数達が書かれています.

github.com

以下は Up 関数の抜粋です.

func (b *Backend) Up(ctx context.Context, options cli.ProjectOptions) error {
    project, err := cli.ProjectFromOptions(&options)
    if err != nil {
        return err
    }

    if b.Cluster != "" {
        ok, err := b.api.ClusterExists(ctx, b.Cluster)
        if err != nil {
            return err
        }
        if !ok {
            return fmt.Errorf("configured cluster %q does not exist", b.Cluster)
        }
    }

    update, err := b.api.StackExists(ctx, project.Name)
    if err != nil {
        return err
    }
    if update {
        return fmt.Errorf("we do not (yet) support updating an existing CloudFormation stack")
    }

    template, err := b.Convert(project)
    if err != nil {
        return err
    }

    vpc, err := b.GetVPC(ctx, project)
    if err != nil {
        return err
    }

    subNets, err := b.api.GetSubNets(ctx, vpc)
    if err != nil {
        return err
    }

    lb, err := b.GetLoadBalancer(ctx, project)
    if err != nil {
        return err
    }

    parameters := map[string]string{
        ParameterClusterName:     b.Cluster,
        ParameterVPCId:           vpc,
        ParameterSubnet1Id:       subNets[0],
        ParameterSubnet2Id:       subNets[1],
        ParameterLoadBalancerARN: lb,
    }

    err = b.api.CreateStack(ctx, project.Name, template, parameters)
    if err != nil {
        return err
    }

    fmt.Println()
    w := console.NewProgressWriter()
    for k := range template.Resources {
        w.ResourceEvent(k, "PENDING", "")
    }
    return b.WaitStackCompletion(ctx, project.Name, compose.StackCreate, w)
}

以下のような順番で AWS リソースの操作が動いていることが解ります.

  1. ECS Cluster が存在するか確認
  2. CloudFormation スタックの確認
  3. CloudFormation テンプレートの生成 (後述)
  4. default VPC が存在しているか確認して, 存在していたら VPC ID を返す
  5. サブネット, ロードバランサの情報を取得
  6. 最後に CloudFormation のスタックを作成

そして, Create Stack が完了するまで待機するという感じだと思います. 個人的に興味深いのは, CloudFormation のテンプレートを生成している部分ですので, この部分を処理しているコードも見てみます.

convert.go

以下は, up.go 内で呼ばれている Convert 関数が実行されている convert.go です.

github.com

convert.go の冒頭の抜粋です.

func (b Backend) Convert(project *types.Project) (*cloudformation.Template, error) {
    var checker compatibility.Checker = &FargateCompatibilityChecker{
        compatibility.AllowList{
            Supported: compatibleComposeAttributes,
        },
    }
    compatibility.Check(project, checker)
    for _, err := range checker.Errors() {
        if errdefs.IsIncompatibleError(err) {
            logrus.Error(err.Error())
        } else {
            logrus.Warn(err.Error())
        }
    }
...

返り値の型を見ると, *cloudformation.Template とあるので, CloudFormation テンプレートを返すことが解ります.

Convert 関数の引数の型として, *types.Project という型が指定されていますが, これは, compose-spec/compose-go プロジェクトで実装されている関数を呼び出すことが出来る型です.

github.com

詳しくは理解出来ていませんが, どうやら docker-compose.yml をパースして各 YAML キーの値を取り出すことを目的としているようです.

以上

せっかく, 新しいリリースを試そうと早起きしましたが, 思わぬところで躓いてしまいリリース自体を試すことは出来ませんでしたが, ecs-plugin がどのように実装しているのか, ほんの少しだけ覗くことが出来ました. 実際に試すことは出来ませんでした, docker コマンドから直接 ECS にアプリケーションがデプロイ出来ることで, 開発からデプロイまでを一貫して行えるようになるというのは非常に嬉しいことだと思いますし, 世界中のエンジニアがまち待った機能なのではないでしょうか.

そして, 早く default VPC 以外でも使えるようになることを祈っています. 以下の通り, issue 化されているので, default VPC 以外でも使える日は近いのかなと期待しております.

github.com

2020 年 07 月 10 日 (金)

アクティビティ (今までの走行 (歩行) 距離)

https://pixe.la/v1/users/inokappa/graphs/fitbit-activity

Fitibit Charge2 のアクティビティから走行 (歩行) 距離を Fitbit Web API で取得して Pixela で草生やしている. 色が濃くなれば濃くなる程強度が高い (歩行, 走行距離が長い) ということで. 実装の詳細はこちら.

ジョギング

朝, 始業前に.

ギョーム

  • ウィークリーレポート書いたり
  • 1on1
  • CloudWatch メトリクスを見ていてエラーレートが気になったので, アプリケーションにプルリクエスト投げた

最近, インフラの調査結果をきっかけにアプリケーションの KAIZEN に繋げられることがチラホラあって良かった. そんなに頻繁にあることではないけど, 今後も少しでもサービスに貢献出来るといいなあ.

ディナー

塩麹で漬け込んだローストポークと彩り季節野菜. 豚が柔らかくて下味もしっかりしていて美味しゅうございました.

2020 年 07 月 09 日 (木)

アクティビティ (今までの走行 (歩行) 距離)

https://pixe.la/v1/users/inokappa/graphs/fitbit-activity

Fitibit Charge2 のアクティビティから走行 (歩行) 距離を Fitbit Web API で取得して Pixela で草生やしている. 色が濃くなれば濃くなる程強度が高い (歩行, 走行距離が長い) ということで. 実装の詳細はこちら.

ジョギング

朝, 始業前に.

ギョーム

  • ECS AMI 更新, 作業自動化の見通しが出来てきた感じ
  • 不要な AWS リソースの整理やら
  • Go で Lambda 関数書いている

ディナー

昨日のハンバーグをデミグラスソースで. 赤ワインやらケチャップやら色々と煮詰まったソースが美味しゅうございました. でも, おろしハンバーグの方が好きだなあ.

Serverless で An error occurred: xxxxxxxxx - A version for this Lambda function exists ( 1 ). Modify the function to create a new version. というエラーが出た場合の対応 (暫定版)

tl;dr

Serverless で, コードを一切変更せずに, serverless.yml の設定だけをイジって (関数にタグを設定した) デプロイ sls deploy したら, 以下のようなエラーが発生して, とりあえず対処したのでメモしておきます.

An error occurred: xxxxxxxxx - A version for this Lambda function exists ( 1 ). Modify the function to create a new version.

とりあえず の対処なので, 正しい対処の方法なのか解っていないので, より良い対策が確認できたら追記したいと思います.

versionFunctions: false

serverless.yml に追加

versionFunctions: false を serverless.yml に追加しました.

---
# yamllint disable rule:line-length

service: sample-application
provider:
  name: aws
  versionFunctions: false
  runtime: go1.x
  region: ap-northeast-1
 
...

この状態でデプロイすることで, 先述のエラーは発生しなくなりました.

versionFunctions について

以下, ドキュメントです.

www.serverless.com

デフォルトでは Lambda 関数はデプロイ毎に新しいバージョンが作成され続けますが, versionFunctions: false を指定することで, これを抑制することが出来ます. デプロイ毎に新しいバージョンが作られなくなることで, 古いバージョンにロールバックしてデプロイすることが出来なくなります.

尚, Serverless ではデプロイの際にコードの sha256 ハッシュ値を計算していますが, このハッシュ値を比較して, バージョンを変更するようです. (ハッシュ値が異なれば新しいバージョンと判断している) 今回のエラーはコードが変更されていないにも関わらず, Serverless が Lambda 関数の新しいバージョンを作成しようとした為に発生したと思われます.

github.com

参考

www.serverless.com

seed.run

以上

色々と解っていないわたくしでございました.

ダウンロードした RDS (PostgreSQL) のスローログで duration とクエリだけを出力するワンライナー

tl;dr

ダウンロードした RDS (今回は PostgreSQL) のスローログを以下のような感じで出力したいと思って試行錯誤したのでメモしておきます.

xxx1.xxx ms SELECT * FROM xxxx WHERE xxx1
xxx2.xxx ms SELECT * FROM xxxx WHERE xxx2
...

一番左の列には経過時間, その後にクエリの文字列全てを出力したいと思います. また, 経過時間が長い順番に降順に出力します.

ちなみに, 実際のログファイルは以下のような文字列になっています.

2020-07-07 09:07:46 UTC:xx.xx.xx.xx(58946):user@db:[1234]:LOG:  duration: 2953.164 ms  execute <unnamed>: SELECT * FROM foo WHERE bar = xxx
2020-07-07 09:08:46 UTC:xx.xx.xx.xx(58946):user@db:[1234]:LOG:  duration: 3053.164 ms  execute <unnamed>: SELECT * FROM foo WHERE bar = xxx

ワンライナー

以下のようなワンライナーを書きました.

$ grep duration postgresql.log.YYYY-MM-DD-HH | cut -d ' ' -f 6- | sort -r -n | sed 's/execute <unnamed>://'

先述の文字列で試してみます.

$ cat /etc/lsb-release
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=18.04
DISTRIB_CODENAME=bionic
DISTRIB_DESCRIPTION="Ubuntu 18.04.3 LTS"

$ cat << EOS | cut -d ' ' -f 6- | sort -r -n | sed 's/execute <unnamed>://'
> 2020-07-07 09:07:46 UTC:xx.xx.xx.xx(58946):user@db:[1234]:LOG:  duration: 2953.164 ms  execute <unnamed>: SELECT * FROM foo WHERE bar = xxx
> 2020-07-07 09:08:46 UTC:xx.xx.xx.xx(58946):user@db:[1234]:LOG:  duration: 3053.164 ms  execute <unnamed>: SELECT * FROM foo WHERE bar = xxx
> EOS
3053.164 ms   SELECT * FROM foo WHERE bar = xxx
2953.164 ms   SELECT * FROM foo WHERE bar = xxx

意図したように出力されました.

キモは cut -d ' ' -f 6- でしょうか.

$ cut --help
Usage: cut OPTION... [FILE]...
Print selected parts of lines from each FILE to standard output.

With no FILE, or when FILE is -, read standard input.

Mandatory arguments to long options are mandatory for short options too.
...
  -d, --delimiter=DELIM   use DELIM instead of TAB for field delimiter
  -f, --fields=LIST       select only these fields;  also print any line
                            that contains no delimiter character, unless
                            the -s option is specified
...

-d はデリミタはスペース, -f は列を指定することになりますが, 6- を指定することで, 6 列目以降を取得しています.

参考

以下の記事を参考にさせて頂きました.

man7.org

blog.cles.jp

ありがとうございました.

以上

メモでした. まだまだ知らないことが多いです.