buto > /dev/null

だいたい急に挑戦してゴールにたどり着かずに飽きる日々です

Webhookってなんだっけ??

先日RDS同士のデータ連携について調べたので打ち合わせで「調べました!」と報告すると「あとWebhookもありだよね」と言われました

あれ?Webhookってなんだったっけ…??

更新情報を他アプリにリアルタイム提供

qiita.com

GitHubにプッシュしたらCodePipelineが動き出す仕組み!JIRA更新した時のslack通知!

そういえば前にRedmine(EC2)でチケット更新したらslack通知する設定した記憶が…

あれがWebhookだったのか

RDS同期への応用方法

dev.classmethod.jp

理想はこうなんだけど

  1. RDSが更新されたらEventBridgeで更新を検知

  2. 更新されたテーブル名、CRUD区分、更新データをlambda引数に渡しもう一方のRDSを更新

EventBridgeでRDS更新は検知できなさそう??(RDSイベントになさそう)

EventBridgeからlambdaに更新したテーブル名とかデータとか渡せるんだろうか??

引数設定を入力トランスフォーマーにしたらいけるかもって思ったけど、入力トランスフォーマーに渡す値はイベントテキスト(定数json)だから無理かも…

時間ある時に苦戦してみるか笑

Goはじめた!!

超今更だけどGo始めてみる!

爆速HelloWorld!

まずはmacにGoをインストール

brew install go

ビルドができるように環境設定を変更(何を変更したのかは今は知らなくていい)

go env -w GO111MODULE=off

ワークスペースにhello.goを作成して以下を書く

package main

import "fmt"

func main() {
    fmt.Printf("hello, world\n")
}

hello.goがあるディレクトリでビルド・実行!

build go
go run hello.go

これで hello, world と表示される!!(いい調子!)

標準モジュールを使ってみる

A Tour of Goの最初の方をざっと読んだので多分書ける!!

AdventCalendar参加者と記事、投稿日を標準出力に表示します

package main

import "fmt"

// 記事struct
type Aritcle struct {
    author   string
    title    string
    postDate string
}

func main() {
    article1 := Aritcle{"buto", "Python 音声ファイルの周波数を取得する", "12/8"}
    article2 := Aritcle{"ys2896", "MySQLのAurora化でMyISAMがなくなって苦戦した話", "12/9"}
    article3 := Aritcle{"yugi0922", "AWSソリューションアーキテクトアソシエイト(SAA) 合格(予定)体験記", "12/12"}
    article4 := Aritcle{"sugiyama_yuta", "DockerでのLaravel×Reactの環境構築について書きます", "12/24"}

    adventCalendar := [4]Aritcle{article1, article2, article3, article4}

    for i, article := range adventCalendar {
        fmt.Printf("AdvendCalendar参加者 %d人目: %s\n", i+1, article.author)
        fmt.Printf("%s %s\n", article.postDate, article.title)
        fmt.Println("******************************")
    }
}

これを go run すると…

AdvendCalendar参加者 1人目: buto
12/8 Python 音声ファイルの周波数を取得する
******************************
AdvendCalendar参加者 2人目: ys2896
12/9 MySQLのAurora化でMyISAMがなくなって苦戦した話
******************************
AdvendCalendar参加者 3人目: yugi0922
12/12 AWSソリューションアーキテクトアソシエイト(SAA) 合格(予定)体験記
******************************
AdvendCalendar参加者 4人目: sugiyama_yuta
12/24 DockerでのLaravel×Reactの環境構築について書きます
******************************

おお〜できました!range を使うと配列のインデックスと要素が簡単に取得できるのでいい!!

CodeDeployでEC2にデプロイしようとした話

先ほどの記事に続きCodePipelineで自動デプロイできるよう直していきます!!

Buildも失敗

やっとSourceが成功したので次はBuild!って失敗かーーーい!

f:id:butorisa:20211219232148p:plain

Error calling startBuild: Bucket ********** does not exist 

ビルド用のバケットがないようだ Source同様作り直してBuild実行!成功しました

f:id:butorisa:20211219232707p:plain

Deploy

デプロイ先のEC2も作り直してまずDeployを実行してみて失敗原因を確認

f:id:butorisa:20211219235518p:plain

最初のタスクで失敗しちゃってますね。。「code deploy stop application 失敗」で検索したら解決策が出てきました!

zenn.dev

あ。そもそもEC2起動しただけでCodeDeployAgentインストールしてなかった笑

dev.classmethod.jp

nodejsとvue.jsもインストールしていなかったのでインストールしておく

qiita.com

それでもエラーが変わらないので手動でデプロイを作成してみた

qiita.com

んーそれでも上手くいかない。。明日またやろう

CodePipelineでS3にソースをダウンロード

去年CodePipelineでvue.jsプロジェクトを自動デプロイしようとしたが最後のデプロイで失敗して放置していたので直してみる!

qiita.com

Source失敗

1年以上寝かせておいたパイプラインを実行すると、なんと最初のGitHubからソースをダウンロードする段階で失敗!残念すぎる!!

エラー詳細を確認すると「S3 bucket was not found」っぽい文言でした

あれ?パイプラインでSource実行時に自動的にバケットって作成されなかったっけ??と思いつつ

S3を確認するとバケット1つもない!去年の自分がバケット消しちゃったんですね。。

Sourceバケット作成

ということでGitHubからダウンロードしたソースを配置するS3バケットを作成する

作成するバケット名はパイプラインの設定-アーティファクトストアで確認

f:id:butorisa:20211219231733p:plain

(とりあえずバケット作っておけばソース配置されるでしょって思って適当な名前にしたらダメだった)

それでは、パイプライン再実行!はい、失敗!

f:id:butorisa:20211219230300p:plain

[GitHub] Upload to S3 failed with the following error: The bucket does not allow ACLs 

アクセスコントロールリストが許可されてないと…

ACL許可のS3バケットを再作成

バケットACL設定はどこで編集するのか分からなかったので(できない?)バケットを再作成

バケット作成画面のここですね デフォルトはACL無効になっていました

f:id:butorisa:20211219230707p:plain

ついでにその下のパブリックアクセス設定も全て許可にしておきました

では再び、Source実行!今度は成功しました!!

f:id:butorisa:20211219231359p:plain

これでやっとスタートライン…

オンプレサーバ間のファイル共有方法

仕事でバックオフィスシステムでアップロードしたファイルがフロントサイトで

どのように参照されるかが知りたいがフロントサイトのコードを追うと該当箇所が多く

時間が足りないのでバックオフィスのアップロード方法だけ確認して、この方法で

アップロードしているからフロントサイトでの参照方法は…と推測できるようにする!

バックオフィス、フロントサイトは別々のオンプレミスサーバです

NFSディレクトリをマウント

baremetal.jp

バックオフィスサーバのNFSディレクトリにファイルをアップロードしているパターン

ファイルアップロード後にファイルにフロントサイトが参照するURL(フロントサイトのドメイン)を発行し

DBにファイル種別(広告バナーなど)とURLを保存していた

フロントサーバでもNFSがマウントされていてDBからファイル種別でURLを取得しHTMLに埋め込めんで表示している

rsyncで転送

アップロードされたファイルをバックオフィスサーバ内に配置しておきrsyncで他のサーバ(多分フロント)に転送しているパターンもあった

転送先はフロントサーバ自身だったら ./img/banner.jpg のように参照している

ただフロントサイトが転送されたファイル名を分からないといけないため、以下のようなルールがあるはず

  • 転送先のディレクトリは「トップページの広告エリアに表示するバナー画像」のように決まったファイル専用となる

  • 転送する1ディレクトリの中に複数のファイルがあり、ファイルの表示を制御したい場合は転送前にファイル名をキー値にする

    • 例えばキャンペーンのhtmlファイルを転送する場合はDBに登録されているキャンペーンID.htmlにする

    • フロントサイトではキャンペーン一覧表示時にDBからキャンペーンデータを取得し、IDから各キャンペーンhtmlを表示するリンクを生成する

結論

DBにファイルアクセス用URLが登録されていたらURL参照、登録されていなかったらフロントアプリでディレクトリ決め打ちしてファイルを取得している!!…はず

GitHub マージ方法の違いを調べた

これまで仕事でマージ方法を指定されたことがないのでマージコミットを作成する方法でマージしていたけど

そろそろ他の種類も理解しておいた方が良さそうなのでGitHubで提供されている3つのマージ方法を試してみた!

マージの準備として以下を行いました

  1. masterからfeature/#1ブランチ作成してカレントブランチにする

  2. コメント行を追加してfeature/#1にコミット・プッシュ

    • f:id:butorisa:20211218141708p:plain
  3. masterからfeature/#2ブランチ作成してカレントブランチにする

  4. 同じ箇所にコメント行を追加してfeature/#2にコミット・プッシュ

    • f:id:butorisa:20211218141753p:plain
  5. Create a merge commit でfeature/#1をmasterにマージ&プッシュ

    • f:id:butorisa:20211218143458p:plain

Create a merge commit

Create a merge commit でfeature/#2をmasterにマージしようとすると先ほどマージした箇所と競合します

f:id:butorisa:20211218143815p:plain

 Create a merge commit を選択すると手動マージしてくださいとのこと(競合箇所が多いと焦るあるあるですね)

f:id:butorisa:20211218144130p:plain

Atomで競合箇所を確認してfeature/#2の修正を選択しマージ・プッシュ!

f:id:butorisa:20211218150640p:plain

マージ先のmasterは新たに作成されたマージコミットの状態になっている(non fast-forwardマージ

f:id:butorisa:20211218151747p:plain

featureブランチを削除してもマージ履歴は枝分かれしています(このマージだったらfeature削除しないほうが履歴が追いやすくて良さそう)

f:id:butorisa:20211218162009p:plain

Squash and merge

再び上記の準備を実施した状態(今度は#3、4ブランチ)

f:id:butorisa:20211218152944p:plain

Squash and merge を選択し先ほど同様に手動マージを行いfeature/#4をmasterにマージ&プッシュ

このマージ方法だと#4ブランチは枝分かれしたままで#3ブランチに#4の修正点が付け足されています(こちらもnon fast-forwardマージになっている)

f:id:butorisa:20211218153113p:plain

masterにマージした後featureブランチを削除すると修正が1本線でされたようになります(feature削除する場合はこちらが良さそう)

f:id:butorisa:20211218161454p:plain

Rebase and merge

最後にrebase編!準備を実施(今度は#7、8ブランチ)masterは#7ブランチの状態

f:id:butorisa:20211218154347p:plain

※#5、6でやってみたが動きがつかめなかったのでリトライ!

Rebase and merge を選択するとまずrebase実行のアラートが出て手動マージ

これまでのマージ方法ではour changesがマージしようとしているブランチの修正だったけどrebaseマージでは逆になっている

(#7ブランチをrebaseするからこちらの修正がour changesになるってことか!rebase解説はこちら

f:id:butorisa:20211218154915p:plain

feature/#8ブランチの修正を選択してマージ&プッシュ!masterはpull1件、push1件になっています

f:id:butorisa:20211218155210p:plain

f:id:butorisa:20211218155300p:plain

fork GUIでpullだけ実行しようとしたらまた競合が発生したのでgithub GUIでforce pushするとリモートmasterが#8の状態になった

f:id:butorisa:20211218160508p:plain

featureを削除すると#7での修正履歴は消え、単純にmaster修正前→#8に修正されたように見える

f:id:butorisa:20211218162719p:plain

f:id:butorisa:20211218162807p:plain

rebaseマージの使いどころが分かっていないがfeatureブランチの修正範囲が大きくコミット回数が多いが、コミット履歴は不要という場合に使えるのかな??

Step FunctionsでLambdaを連続実行してみる

AWS StepFunctionsがどんなサービスか分かったので使ってみる!

StepFunctionsで実現することはこちら

  1. おくすり登録lambda関数(引数に薬の名前・服用回数を受け取り、薬の名前と服用タイミングを返す)

  2. リマインダーlambda関数(引数に開始時間・イベント名を受け取り、SES送信)

これだけだったら普通にlambdaの連続実行でいいんですけどね^^;

なんちゃってマイクロサービスでリマインダー機能は独立させておいて今後の(あるか分からない)機能拡張により

レッスン予定登録、資格勉強タスク登録…など他の機能からも汎用的に実行できる構成にしたということで!!

Lambda関数を作成

おくすり登録関数

引数はこんな感じ

{
  "name": "ステロイド1/6錠",
  "timesDaily": "2"
}
exports.handler = async(event) => {

    let start;

    if (event.timesDaily == 1) {
        start = "15:00";
    }
    else if (event.timesDaily == 2) {
        start = "10:00, 17:00"
    }
    else if (event.timesDaily == 3) {
        start = "10:00, 15:00, 20:00"
    } else {
        return
    }

    const response = {
        statusCode: 200,
        start: start,
        title: "[おくすり]" + event.name
    };
    return response;
};

リマインダー関数

// Load the AWS SDK for Node.js
var AWS = require('aws-sdk');
// Set the region 
AWS.config.update({ region: 'ap-northeast-1' });

// Create sendEmail params 
var params = {
    Destination: { /* required */
        CcAddresses: [],
        ToAddresses: [
            'メールアドレス',
        ]
    },
    Message: { /* required */
        Body: { /* required */
            Html: {
                Charset: "UTF-8",
                Data: "HTML_FORMAT_BODY"
            },
            Text: {
                Charset: "UTF-8",
                Data: "TEXT_FORMAT_BODY"
            }
        },
        Subject: {
            Charset: 'UTF-8',
            Data: 'my reminder'
        }
    },
    Source: 'メールアドレス',
    /* required */
    ReplyToAddresses: [],
};

// Handle promise's fulfilled/rejected states
exports.handler = function(event, context, callback) {
    params.Message.Subject.Data = "[reminder]" + event.start + event.title;
    params.Message.Body.Html.Data = "本日のスケジュール<br>" + event.start + " : " + event.title;
    params.Message.Body.Text.Data = "本日のスケジュール¥n" + event.start + " : " + event.title;
    return new AWS.SES({ apiVersion: '2010-12-01' }).sendEmail(params).promise();
}

関数をStepFunctionsで実行

それでは作成した2つの関数をStepFunctionsから連続実行してみます!

ステートマシン(StepFunctionsで実行する処理をまとめたもの)を作成して実行すればOK

マネジメントコンソールからステートマシン作成をすると作成方法が選択できる

これまではjsonを書いて作成していたみたいだけど、このようにフロー図にドラッグ&ドロップで簡単配置★!

f:id:butorisa:20211218111404p:plain

ステートマシンが作成できたのであとは実行するだけ って失敗してる!

f:id:butorisa:20211218111855p:plain

because no identity-based policy allows the lambda:InvokeFunction action

いつも通り実行ロールがないエラーですね。(AWSで何か試そうとすると遭遇率100%なんだよな。。)

AWSLambdaRoleをアタッチして再度実行!今度は正常終了しました

f:id:butorisa:20211218113130p:plain

リマインドのメールも届きました!

f:id:butorisa:20211218113447p:plain