LoginSignup
0
0

More than 1 year has passed since last update.

aws cdkでecsタスクスケジュールによるバッチ機構を作る

Last updated at Posted at 2022-06-01

はじめに

みなさん、障害対応してますか?

障害対応に関しての私のモットーは、
アラートがとんで来たら、まずはコーヒーを淹れて、
鼻から抜ける豆の香りを堪能してからパソコンを開く事です。

おかげで、後々作成する謝罪文も芳醇でマイルドなものになります。

ことAWSの話しですが、ここ数ヶ月
コーヒーのフルーティな味わいを感じながら原因調査してると、
かなり序盤の方で
「これホスティング側の問題じゃない?」って頭に浮かぶ事があります。

しかしながらHealthDashboardは音沙汰なく、
「あれ、やっぱりこっちの問題???...」となり、もっかい色々みてみる、
なんてケースが多々あります。

そんな時ちらっとtwitterみると、

「AWS障害か〜〜仕方ないから今日休みにしない?」
「aws 落ちてんじゃん、ネトフリみて待ってよ」

といった考えられないツイートもあれば、
どのリージョンでどのリソースがあやしそうか探ってる人なんかもいます。

怪しいな、と思ったらtwitterがざわざわガヤガヤしてないか見てみるのも手だなと。

そこで、定期的に特定ワードが頻繁につぶやかれてる時、
その事を通知してくれる物を用意しておけば、
原因特定はそこそこに、次の一杯を淹れに影響調査の方に時間をさけるというものです。

という事で、そんな通知ボットを作りましょう。というのが前段。

長くなりましたが、目的は後付で、
cdkでecsタスクを定期実行する何かを作ってみようとしたという所が正直な所です。
docker、ecs周りの基本的内容の復習がほとんどです。

この記事でやってる事

  • twitterのAPIを使って記事を検索するスクリプトをTypeScriptで用意
  • 上記を定期実行するリソース一式をcdkで作る

目次

  • twitter検索機能を作る
  • docker化してみる
  • fargateで動かしてみる
  • まとめ

twitter検索機能を作る

まずはDeveloperアカウントの用意

詳しくは省きますが、公式さん の言う通りに進めます。
色々聞かれますが、作成したら Bearer Token がもらえます。これ使うのでひかえておきます。

Screenshot 2022-06-01 1.04.59.png

TypeScriptのセットアップ

公式さん を見ると、
APIのv2の TypeScript/JavaScriptSDK が存在しているようなので、
そちらを使う為にTypeScriptで書く事にします。

まずはプロジェクトのセットアップ

ちなみに自分の環境は以下

  • PC: mac(Monterey) Apple Silicon
  • node: 18.1.0
  • npm: 8.8.0
  • 手元のコーヒー: ブルーマウンテンブレンド 330円
# プロジェクト作成
mkdir app && cd app

# package.json作る 
npm init

# typescript入れる
npm install --save-dev typescript

# tsconfig.json作る
npx tsc --init

いちいちトランスパイルするのも面倒なのでts-nodeを入れて、TypeScriptを直実行できるようにしておきます

npm install --save-dev ts-node

試しにtsファイルを作って、直実行してみます

app/index.ts
const runningTest: string = "「He~~llo」(・ω| ←SigourneyWeaver"
console.log(runningTest)
npx ts-node hello.ts

> 「He~~llo」(・ω| ←SigourneyWeaver

問題なさそうですね。

npx ts-node は、 ./node_modules/.bin/ts-node と同義です。
いちいちmodulesを指定しなくてもいいという。npx、便利ですね。
インストールしてないモジュールも指定できるのだそう(使ったあと消える)

twitterのSDK入れる

次にsdkを公式さんの言う通りに入れます

npm install twitter-api-sdk

そしてこんな感じでindex.tsを改変します。
後々そうするので、tokenなんかは環境変数で渡してます

app/index.ts
import {Client} from "twitter-api-sdk";

const bearerToken = process.env.BEARER_TOKEN as string;
const client = new Client(bearerToken);
const now = new Date();
now.setHours(now.getHours() - 1); // 試しに直近1時間までのツイートを対象に

async function search() {
    const response = await client.tweets.tweetsRecentSearch({
        'query': 'なかやまきんに君', // ここに検索したいワードを入れる
        'start_time': now.toISOString(),
        'tweet.fields': [
            'created_at'
        ]
    });

    return response.data;
}

// 実行
search().then(tweets => {
    if (tweets === undefined) {
        console.log('取得結果なし')
        process.exit(1);
    }

    for (const tweet of tweets) {
        console.log(tweet);
    }
});

走らせてみます。

BEARER_TOKEN=twitterに発行してもらったトークン \
npx ts-node index.ts

kinikun_run.png

うん、動作良好ですね。

slack通知したいので、モジュール追加します

npm install @slack/web-api

ファイルがでかくなりそうなので、分けます。

app/lib/TweetChecker.ts
import {Client} from "twitter-api-sdk";
import {WebClient} from "@slack/web-api";

export class TweetChecker {
    private TWITTER_URL_BASE: string = 'https://twitter.com/dummy/status/TWEET_ID';
    private readonly client: Client;
    private readonly query: string;
    private readonly slackToken: string;
    private readonly slackChannel: string;

    constructor(
        bearerToken: string,
        query: string,
        slackToken: string,
        slackChannel: string
    ) {
        this.client = new Client(bearerToken);
        this.query = query;
        this.slackToken = slackToken;
        this.slackChannel = slackChannel;
    }

    checkTweets() {
        this.recentSearch().then(tweets => {

            if (tweets === undefined) {
                console.log('世界は平和でした。');
                return;
            }

            let tweetUrls: Array<string> = [];
            for (const tweet of tweets) {
                let tweetUrl = this.TWITTER_URL_BASE.replace('TWEET_ID', tweet.id);
                tweetUrls.push(tweetUrl);
            }

            this.post(tweetUrls).then(() => {
                console.log('succeed');
            });
        });
    }

    private async recentSearch() {
        const now = new Date();
        now.setHours(now.getHours() - 12);

        const response = await this.client.tweets.tweetsRecentSearch({
            'query': this.query,
            'max_results': 10,
            'start_time': now.toISOString(),
            'tweet.fields': [
                'created_at',
                'entities'
            ]
        });

        return response.data;
    }

    private async post(tweetUrls: Array<string>) {
        let message = '';
        message += '.....おや!?' + "\n"
        message += "AWSのようすが.....!" + "\n\n"
        message += "   ↓ ↓ ↓ ↓" + "\n\n"
        message += tweetUrls.join("\n");

        const client = new WebClient(this.slackToken);
        return await client.chat.postMessage({
            channel: this.slackChannel,
            text: message
        });
    }
}

index.tsは、環境変数受け取ってclassを呼ぶだけにしておきます

app/index.ts
import {TweetChecker} from "./lib/TweetChecker";

const bearerToken = process.env.BEARER_TOKEN as string;
const searchQuery = process.env.SEARCH_QUERY as string;
const slackToken = process.env.SLACK_TOKEN as string;
const slackChannel = process.env.SLACK_CHANNEL as string;

const twitterClient = new TweetChecker(
    bearerToken,
    searchQuery,
    slackToken,
    slackChannel
);
twitterClient.checkTweets();

もっかい実行してみます。

↓↓↓

BEARER_TOKEN=twitterに発行してもらったトークン \
SEARCH_QUERY='AWS障害 OR AWS落ちた' \
SLACK_TOKEN=スラックトークン \
SLACK_CHANNEL=#すきなチャネル \
npx ts-node index.ts

slack_通知君.png

OKOK。
まあここで色々対象ツイート絞ったり色々すべきですが、
はじめに言った通り、やりたかったのここからなので、
これはもうこれで終わりにします。

docker化してみる

次に、作ったものをdockerImageにします。

appディレクトリ直下にDockerfileを作成します。
今回はオフィシャルのnodeイメージを使います。

app/Dockerfile
FROM node:latest

# ワークディレクトリを設定
WORKDIR /usr/run/app

# appディレクトリを一式コピー(不要な物はdockerignoreしてちょっとでも軽く)
COPY . .

# npm installする
RUN npm install

# npx ts-node index.ts走らせる
CMD [ "npx", "ts-node" , "index.ts" ]

COPY . .はやりすぎですが、一応dockerignoreでイメージの中に入れたくないものは記載しておきます。

app/.dockerignore
/node_modules
/Dockerfile
/.dockerignore

さあ、ビルドしてみます。

docker build -t search-tweet .

狙ったものが入ってるか、中入ってみてみましょう。

docker run -it --rm \
--name test-search-tweet search-tweet \
/bin/bash
root@90170d1c165f:/usr/run/app# ls
index.ts  lib  node_modules  package-lock.json	package.json  tsconfig.json

うんうん、期待値。

ではrunしてみます。
先程直接指定していた環境変数は、コンテナ側に持っていく必要があるので、
こんな感じでファイルに書き出して、
run する時のオプションで指定してあげます。

app/app.env
BEARER_TOKEN=twitterに発行してもらったトークン
SEARCH_QUERY='AWS障害 OR AWS落ちた'
SLACK_TOKEN=スラックトークン
SLACK_CHANNEL=#すきなチャネル

では実行

docker run -it --rm \
--env-file=app.env \
--name test-search-tweet search-tweet

Screenshot 2022-06-01 2.51.17.png

コンテナからも実行できました。

さあこれで準備は整いました。
いよいよfargateで動いてもらいましょう。

fargateで動かしてみる

さてawsリソース一式作るために、cdkの登場ですが、その前に

cdk is 何

まずはそこです。

いろいろ詳しい私の友人に聞いてみます。


toolkit.png

知らないみたいです。

公式さんによると、
AWS Cloud Development Kitの略だそう。
ざっくりいうと、プログラミング言語でCloudFormationテンプレートが掛けるとの事。
同じようなリソースならぶ時はループとかで書けるって事です。やほーい。

何よりデフォで色々おすすめ初期設定が入ってるから、
簡単なリソースならめっちゃシンプルにかけます。
ここが便利であり怖いとこかなと。

cdkセットアップ

ではさっそくセットアップ。

今こんな感じのディレクトリになってるので、

app/ ←ここ
├── index.ts
├── lib
│   └── TweetChecker.ts
├── node_modules
├── package-lock.json
├── package.json
└── tsconfig.json

一個もどってcdkディレクトリ作ります。そして初期化。
いくつか言語使えますが、今回は同じくTypeScriptで。

cd ../ && mkdir cdk && cd cdk

# 初期化
cdk init --language typescript
cdk/
├── README.md
├── bin
│   └── cdk.ts
├── cdk.json
├── jest.config.js
├── lib
│   └── cdk-stack.ts
├── package-lock.json
├── package.json
├── test
│   └── cdk.test.ts
└── tsconfig.json

いろいろ入りました。 v2が入ったようです。
lib/cdk.ts にスタックを記載し、 bin/cdk.ts でそれらをnewする感じになります。
あと環境差分値なんかはcdk.jsonに書くことになるかなと

ひとまずcdk bootstrap

cdkを使うには、cdk bootstrap しておく必要があります。

リソースを作るリージョン毎に必要で、
実行するとデフォルトでは CDKToolkit という名前のスタックが作成されます。
cdkの成果物はCloudFormationテンプレートですが、
CFnもテンプレートサイズがでかすぎる場合はs3に一度テンプレートを配置する必要があり、
その時などに使うs3バケットなんかがこれにより作成されます。

Screenshot 2022-06-01 3.29.18.png

↓↓ 作られる ↓↓

toolkit.png

↓↓ 中身 ↓↓

toolkit_detail.png

これで準備はokなので進みます

スタックの中身を書いていく

cdk/lib/cdk-stack.ts
import {Stack, StackProps} from 'aws-cdk-lib';
import {Construct} from 'constructs';
import {SubnetType} from "aws-cdk-lib/aws-ec2";
import {Cluster, ContainerImage, FargatePlatformVersion, LogDriver} from "aws-cdk-lib/aws-ecs";
import {ScheduledFargateTask} from "aws-cdk-lib/aws-ecs-patterns";
import {Repository} from "aws-cdk-lib/aws-ecr";
import {Schedule} from "aws-cdk-lib/aws-events";

export interface SearchTweetStackProps extends StackProps {
    bearerToken: string;
    searchQuery: string;
    slackToken: string;
    slackChannel: string;
}

export class SearchTweetStack extends Stack {

    constructor(scope: Construct, id: string, props: SearchTweetStackProps) {
        super(scope, id, props);

        // dockerイメージの配置場所を作る
        const ecrRepository = new Repository(this, 'searchTweetRepository', {
            repositoryName: "search-tweet-repo",
            imageScanOnPush: true
        });

        // ECSのクラスタを作る
        const cluster = new Cluster(this, 'SearchTweetECSCluster', {});

        // タスクスケジュールを組む
        const scheduledTask = new ScheduledFargateTask(this, 'SearchTweetScheduledTask', {
            cluster: cluster,
            platformVersion: FargatePlatformVersion.LATEST,
            schedule: Schedule.expression('cron(0/10 * * * ? *)'),
            scheduledFargateTaskImageOptions: {
                image: ContainerImage.fromEcrRepository(ecrRepository, 'latest'),
                memoryLimitMiB: 512,
                cpu: 256,
                logDriver: LogDriver.awsLogs({streamPrefix: 'ScheduledTaskLogs'}),
                environment: {
                    BEARER_TOKEN: props.bearerToken,
                    SEARCH_QUERY: props.searchQuery,
                    SLACK_TOKEN: props.slackToken,
                    SLACK_CHANNEL: props.slackChannel,
                },
            }
        });
    }
}

驚くべきコード量のすくなさ,,,
まあ指定すべきvpcとかほとんどデフォルトっていうのもあるのですが、これだけです。
実際に作られるリソースはもっと多いです、ここで記載しているのは、
ECSクラスターとタスクスケジュールくらいなので余計スッキリしてますね。

そして今までさんざん無理やり渡していた環境変数ですが、
ここで scheduledFargateTaskImageOptions のオプションとしてタスクに引き渡します。
まあこれで渡したかっただけです。

次にメインとなるcdk.tsを変更します

cdk/bin/cdk.ts
#!/usr/bin/env node
import 'source-map-support/register';
import * as cdk from 'aws-cdk-lib';
import {SearchTweetStack, SearchTweetStackProps} from '../lib/cdk-stack';

// props作成
const props: cdk.StackProps = {
    env: {
        account: process.env.CDK_DEFAULT_ACCOUNT,
        region: "ap-northeast-1",
    }
};

// cdk呼ぶ
const app = new cdk.App();

// cdkコマンドで指定したenvの値を取得
const env: string = app.node.tryGetContext("env");

// cdk_jsonに記載したcontext情報を取得
const envProps = app.node.tryGetContext(env);

// propsと自前propsを展開して一つにする
const customProps: SearchTweetStackProps = {
    ...props,
    ...envProps
};

// スタックを作る
new SearchTweetStack(
    app,
    `SearchTweetStack`,
    customProps
);

ここ、環境変数をlibのtsに渡したいわけですが、
cdkのContextの仕組みを使って注入します。

cdk/cdk.json
{
  "app": "npx ts-node --prefer-ts-exts bin/cdk.ts",
  "~~~~~~~",
  "割愛",
  "~~~~~~~", 
  "context": {
    "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true,
    "~~~~~~",
    "割愛",
    "~~~~~~",
    "@aws-cdk/core:target-partitions": [
      "aws",
      "aws-cn"
    ],
    "test": { <-- ここ
      "bearerToken": "twitterから発行されたトークン",
      "searchQuery": "AWS障害 OR AWS落ちた",
      "slackToken": "スラックのトークン",
      "slackChannel": "好きなチャネル"
    }
  }
}

こんな感じで記載しておくことで、
cdkコマンド実行時にcdk.jsonに書いといた値がとれるわけです。
今回機密情報記載しちゃってるのでNGですが、
環境差分値なんかはこれで渡してあげると、prod用stg用なんかを分けてあげられます。

cdk/bin/cdk.ts
// cdk_jsonに記載したcontext情報を取得
const envProps = app.node.tryGetContext(env);

試しに↑↑のenvPropsをconsole.logしておいて、
cdk synthでテンプレートを出力してみます。

cdk synth -c env=test

Screenshot 2022-06-01 3.45.45.png

うまくとれてますね。

一体何が生成されるのか

スタック作成前に、いかなるテンプレートを生み出そうとしてるのか確認しておきましょう。

先程の cdk synth コマンドを使います。
ちょっとテンプレートを書き出してみましょう。

cdk synth -c env=test > template.yaml

割愛しますが、約500行くらいのテンプレートができあがってました。。

Screenshot 2022-06-01 4.08.26.png

中身みてみると、クラスタのvpcを指定してないせいで、新規のvpcを作成してくれてる為、
SubnetやそれぞれのRouteTableなんかも全部用意する方向のようです。

この、よしなにやってくれる所、
根本を把握してないと痛い目みる事がありそうですね。

実際にテンプレートの差分とか見てないと、 ???となる事多そうです。

よくテンプレートをみてみる

出来上がったテンプレートをみてみると、
NATGateWayが2本できてました。

ん?と思って更にみると、

クラスタをPrivateSubnetに配置しようとしてくれているみたいです。

まあ基本確かにそうですよね。

更にはありがたい事に、
Public、PrivateのSubnetをマルチAZになるよう、2つのAZに作成してくれてました。
そしてPrivateSubnetそれぞにNATを作るという流れの模様。

はい、たしかに推奨設定で作ってくれました。

しかし今はテストしたいだけなのでTooマッチです。
NATGateWayは存在するだけでお金かかりますし。

今回はただのテスト開発ですぐ消つもりでいて、かつ、
一応twitterとslack叩くので外には出れてほしいという事で、

  • クラスタはパブリックに配置
  • マルチAZにしない
  • もちろんNATGateWayつくらない

といった具体に変更しに行きます。

スタックの修正

最終版はこちら

cdk/lib/cdk-stack.ts
import {Stack, StackProps, Fn, Aws, aws_ec2} from 'aws-cdk-lib';
import {Construct} from 'constructs';
import {SubnetType,Vpc} from "aws-cdk-lib/aws-ec2";
import {Cluster, ContainerImage, FargatePlatformVersion, LogDriver} from "aws-cdk-lib/aws-ecs";
import {ScheduledFargateTask} from "aws-cdk-lib/aws-ecs-patterns";
import {Repository} from "aws-cdk-lib/aws-ecr";
import {Schedule} from "aws-cdk-lib/aws-events";

export interface SearchTweetStackProps extends StackProps {
    bearerToken: string;
    searchQuery: string;
    slackToken: string;
    slackChannel: string;
}

export class SearchTweetStack extends Stack {

    constructor(scope: Construct, id: string, props: SearchTweetStackProps) {
        super(scope, id, props);

        // dockerイメージの配置場所を作る
        const ecrRepository = new Repository(this, 'searchTweetRepository', {
            repositoryName: "search-tweet-repo",
            imageScanOnPush: true
        });

        // クラスタを配置するVPCを作る
        const vpc = new Vpc(this, 'searchTweetVpc', {
            natGateways: 0, // natGatewayなし
            maxAzs: 1, // シングルAZ
            subnetConfiguration: [ // publicのサブネットを一つ
                {
                    cidrMask: 28,
                    name: 'public',
                    subnetType: SubnetType.PUBLIC,
                },
            ],
        })

        // ECSのクラスタを作る
        const cluster = new Cluster(this, 'SearchTweetECSCluster', {
            vpc // vpcを指定
        });

        // タスクスケジュールを組む
        const scheduledTask = new ScheduledFargateTask(this, 'SearchTweetScheduledTask', {
            cluster: cluster,
            platformVersion: FargatePlatformVersion.LATEST,
            schedule: Schedule.expression('cron(0/10 * * * ? *)'),
            subnetSelection: {subnetType: SubnetType.PUBLIC}, // publicにサブネットに配置するように修正
            scheduledFargateTaskImageOptions: {
                image: ContainerImage.fromEcrRepository(ecrRepository, 'latest'),
                memoryLimitMiB: 512,
                cpu: 256,
                logDriver: LogDriver.awsLogs({streamPrefix: 'ScheduledTaskLogs'}),
                environment: {
                    BEARER_TOKEN: props.bearerToken,
                    SEARCH_QUERY: props.searchQuery,
                    SLACK_TOKEN: props.slackToken,
                    SLACK_CHANNEL: props.slackChannel,
                },
            }
        });
    }
}

差分的は以下で、初期値だった物を明示的に指定しているのみです

差分
@@ -24,15 +24,30 @@ export class SearchTweetStack extends Stack {
             imageScanOnPush: true
         });

+        // クラスタを配置するVPCを作る
+        const vpc = new Vpc(this, 'searchTweetVpc', {
+            natGateways: 0, // natGatewayなし
+            maxAzs: 1, // シングルAZ
+            subnetConfiguration: [ // publicのサブネットを一つ
+                {
+                    cidrMask: 28,
+                    name: 'public',
+                    subnetType: SubnetType.PUBLIC,
+                },
+            ],
+        })
+
         // ECSのクラスタを作る
-        const cluster = new Cluster(this, 'SearchTweetECSCluster', {});
+        const cluster = new Cluster(this, 'SearchTweetECSCluster', {
+            vpc // vpcを指定
+        });

         // タスクスケジュールを組む
         const scheduledTask = new ScheduledFargateTask(this, 'SearchTweetScheduledTask', {
             cluster: cluster,
             platformVersion: FargatePlatformVersion.LATEST,
             schedule: Schedule.expression('cron(0/10 * * * ? *)'),
+            subnetSelection: {subnetType: SubnetType.PUBLIC}, // publicにサブネットに配置するように修正
             scheduledFargateTaskImageOptions: {
                 image: ContainerImage.fromEcrRepository(ecrRepository, 'latest'),
                 memoryLimitMiB: 512,

再度テンプレートを書き出してみましょう。

cdk synth -c env=test > template2.yaml

500行くらいが 300行くらいになりました。
NatGatewayもいません
これで安心。

いざ、デプロイ!!

さてさて、いよいよデプロイします。

cdk deploy -c env=test

ホントに作るよ?? と、もう一度聞いてくれますので、
よろしくおねがいしまーす!!
と、大きい声で叫びながら y を押します。

IAMやSGなんかの差分を改めて出してくれます。

Screenshot 2022-06-01 3.33.44.png

数分くらいで出来上がりました。

これで準備は完了と行きたい所ですが、

lib/cdk-stack.tsScheduledFargateTaskには、search-tweet-repoの名前で作ったECRのlatestタグがついたimageを使ってね。と伝えてあります。

そうです、イメージ配置してませんね。

のでimage作ってECRにpushします。

ECRにタスクが使うimageをアップする

ホントにできてるかまずはECRをみてみましょう。

Screenshot 2022-06-01 4.43.15.png

居ました。

タスク定義の方もみてみましょう。

Screenshot 2022-06-01 4.44.45.png

はいはい確かにこのレポジトリみてますね。

このままでは、
タスクが走りだした時、ガチギレされる事間違いないです。

のでビルドしてpushしておきます。

# appまで移動
cd app

# アカウントID取得して
AWS_ACCOUNT_ID=$(aws sts get-caller-identity | jq -r .Account)

# Loginして
aws ecr get-login-password --region ap-northeast-1 | docker login --username AWS --password-stdin ${AWS_ACCOUNT_ID}.dkr.ecr.ap-northeast-1.amazonaws.com

# ビルドして
docker build -t search-tweet-repo:latest .

# タグ付けして
docker tag search-tweet-repo:latest ${AWS_ACCOUNT_ID}.dkr.ecr.ap-northeast-1.amazonaws.com/search-tweet-repo:latest

# pushする
docker push ${AWS_ACCOUNT_ID}.dkr.ecr.ap-northeast-1.amazonaws.com/search-tweet-repo:latest

ちなみに、ビルドする際、お使いのPCがmacでかつApple Silicon(M1)だった場合、
タスクの起動で失敗しますので、 --platform amd64 を指定してください。
生成されたimageのCPUのアーキテクチャが異なってしまうので、
amd64のCPUで動くようにしてあげる必要があります。
まったくM1のくせに笑えない冗談です。

pushできたか確認します。

aws ecr describe-images --repository-name search-tweet-repo | jq .

>      "repositoryName": "search-tweet-repo",
>      "imageDigest": >"sha256:71cba306c79ffd148d44b331e6a0e11cee3daf7304e098647dbf71f913399410",
>      "imageTags": [
>        "latest"
>      ],

ふむふむできていますね。

そうこうしている内に、タスクが実行された模様です。

Screenshot 2022-06-01 5.06.57.png

タスクのログにもconsole.logした値が入ってました。めでたしめでたし。

Screenshot 2022-06-01 5.02.38.png

気が済んだので消します

cd cdk
cdk destroy

Screenshot 2022-06-01 5.10.29.png

消すよ...? と聞かれるので、
空から降ってきた女の子を探し、そっと手を重ねてから
キリッとした顔をして 「バルス」 と言い、
y を押します。

まとめ

やりたかったのは、何かしらのコマンド機構をECSで定期実行してみるという事でした。

まだサーバのcrontabで動かしてたりするものがあれば、
App部分をそのままimageにしてしまえば、簡単にcronをサーバから切り出せます。
それを実感したかった次第です。

fargateで組んでしまえば、立ち上がりはすぐですので、
長ーーーい処理でない限り、起動時間はごくわずかなはずです。

1時間あたりの起動時間の料金が0.01USDとかなので、
ほとんどお金に跳ねて来ないかなと。

次にcdkですが、めちゃ便利ですね!
デフォで推奨設定を入れてくれる所が光ってます。
ただ便利ですけどまずはCloudFormationを素で書けるくらいになってから使う方がよいですね。

ORMで作ったSQLは吐き出して確認しましょう、というのと同じノリで、
きっとcdk使うときは、 cdk synth を叩きまくるのでしょう。

最後に

今回、機密情報(トークンとか)を
cdk.json ⇨ タスク定義 ⇨ タスク ⇨ コンテナ ⇨ app の経路で渡しちゃってますのでご注意を。
タスク定義みればconsoleから丸見えです。SecretsManager絡めましょう。

あと振り返ると、tsファイルをトランスパイルしないで最後まで行ってしまいました。。
dockerfile内でjsにしてあげてコンテナは実行するのは node index.js にしてあげるべきでした。

そしてずっと謎なのが、
twitterAPIのsearch/recentエンドポイントで取得した検索結果と、
実際にwebの検索から取得した結果が異なるのです、、、
これがずっと解決せず。。。どなたか知ってる方いたら教えてください。

具体的には AWS 障害 とかで検索すると、
この方のtweetはAPIからしか取得できぬのです。
↓ ↓ ↓ ↓

機械的に投稿してる模様なのでそういうのはwebやアプリでは弾いてるのか??

めっちゃ長くなった..
読んでくださった方はありがとうございます。
是非飲みに行きましょう。

参考文献

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0