4
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

AWS Fargate Spot を使う前のメモ

Posted at

AWS Fargate Spotとは

  • Fargate価格から最大70%割引
  • EC2スポットインスタンスとコンセプト自体は同じ
  • AWSクラウドの空きキャパシティを活用してタスクを実行できる
  • AWSがキャパシティを必要とした時、Fargate Spotで稼働するタスクは2分前の通知とともに中断される
  • 常時稼働すべきタスクとFargate Spotで稼働するタスクを併用して構成することができる

Fargate Spotを利用する場合、ECSクラスターを作成する際にキャパシティープロバイダーを指定する必要があります。

キャパシティープロバイダーとは

  • キャパシティープロバイダー戦略で使用されて、タスクが実行されるインフラストラクチャを決定する
  • 各クラスターには1つ以上のキャパシティープロバイダーがある

Fargateの場合、FARGATEFARGATE_SPOTという2つのキャパシティープロバイダーがあります。これらは予約されているため、作成する必要がありません。

キャパシティープロバイダー戦略とは

  • クラスターの複数のキャパシティープロバイダー間にタスクを分散する方法を決定する
  • 各クラスターにはデフォルトのキャパシティープロバイダー戦略が関連づけられている

ECSタスクの正常なシャットダウン(Graceful Shutdown)

Fargate SpotではAWSの都合でタスクが中断されるため、タスク終了の2分前の通知を受けた後、必要に応じてタスクは正常なシャットダウン(Graceful Shutdown)を開始する必要があります。

タスクが停止するとき、SIGTERMシグナルが各コンテナのエントリプロセス(PID:1)に送信されます。

タイムアウトが経過すると、今度はSIGKILLシグナルがプロセスに送信されます。

デフォルトではタイムアウト値は30秒なので、SIGTERMシグナルが送られてからSIGKILLシグナルが来るまでの30秒の間にプロセスを正常にする必要があります(タイムアウト値を変更することは可能)。

Graceful Shutdownを模擬的に試してみる

コンテナではDockerfileENTRYPOINTおよびCMDディレクティブで指定されたプロセスがここでいうエントリプロセスであり、コンテナ内の他の全てのプロセスの親となります。

ここではExpress (Node.js) の Graceful shutdownの記事をそのまま参考にさせて頂き、express.jsでwebサーバーを実行してみます。

index.js
const express = require('express');

const SLEEP_MSEC = 30 * 1000;
const app = express();

app.get('/sleep', (req, res) => {
  setTimeout(() => res.send('OK'), SLEEP_MSEC);
});

const server = app.listen(3000, () => console.log('Example app listening on port 3000!'));

process.on('SIGTERM', () => {
  server.close(() => {
    console.log('Process terminated.')
  })
});
Dockerfile
FROM node:14
ENV LANG C.UTF-8

WORKDIR /usr/src/
ADD package.json package.json
ADD package-lock.json package-lock.json
RUN npm install

ADD index.js index.js

EXPOSE 3000

CMD ["node", "index.js"]
docker-compose.yml
version: "3"

services:
  api:
    build:
      context: ./api
      dockerfile: Dockerfile
    working_dir: /usr/src
    ports:
      - "3000:3000"

docker-compose upで立ち上げた後、docker-compose exec api /bin/bashで入った後、ps auxで確認すると、

USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  0.1  0.9 598316 37272 ?        Ssl  09:17   0:00 node index.js
root        15  0.1  0.0  19952  3540 pts/0    Ss   09:20   0:00 /bin/bash
root        25  0.0  0.0  38384  3064 pts/0    R+   09:21   0:00 ps aux

node index.jsがエントリプロセスになっていることが確認できます。

ここでcurl http://localhost:3000/sleepすると10秒後にレスポンスが返ってきますが、その10秒の間にwebサーバーに対してkill 1でSIGTERMシグナルを送ってみます。
その直後、同じくcurl http://localhost:3000/sleepすると、下記のようにサーバーからレスポンスが返ってこなくなりました。

> curl http://localhost:3000/sleep
curl: (52) Empty reply from server

一方で。10秒経つと最初のリクエストに対するレスポンスが返ってきました。

> curl http://localhost:3000/sleep
ok

つまり、SIGTERMシグナル受信前の処理中のリクエストは正常に処理を完了し、SIGTERMシグナル受信後に来た新規のリクエストは受け付ないようになっています。

→ ECSタスクがSIGTERMシグナルを送ってきた時も同じ挙動を想定して良い?

ロードバランサーを使っている場合、ターゲットグループからタスクを自前で解除する必要がある

FARGATE_SPOT として実行されるタスクでは、ロードバランサーのターゲットグループから登録解除されてからタスクが STOPPED 状態に移行するという保証はありません。
https://aws.amazon.com/jp/blogs/news/graceful-shutdowns-with-ecs/

FARGATE_SPOTの場合、自前で登録解除するロジックをSIGTERMハンドラーに含めたりする必要がある。

参考

4
2
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
4
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?