ALB(Application Load Balancer)を AWS CLI で作るときは、aws elbv2 の 5 つのコマンドを「ロードバランサー → ターゲットグループ → ターゲット登録 → リスナー → ルール」の順に実行します。 後ろのコマンドは前のコマンドが返す ARN を必要とするので、--query で ARN を変数に受け取りながら進めるのがコツです。

この記事では、5 つのコマンドを 1 本のスクリプトにまとめて実行した出力を載せ、ヘルスチェックのオプション、ルールの条件とアクションの JSON、作成時に出やすいエラー文、そして依存関係に沿った削除の順番までを扱います。

確認環境:Ubuntu 24.04、AWS CLI 1.46.1、Python 3.11。AWS の API をローカルで再現するツール(moto 5.2.3)で実行しました。掲載するコマンドは、ローカル向けの接続先指定を外して AWS でそのまま使える形にしています。アカウント ID は例示用の 123456789012 です。

ALB 作成コマンドの早見表

作る順番と、それぞれが何を必要とするかを先に押さえます。

順 作るもの コマンド 必要なもの 受け取る値
1 ロードバランサー aws elbv2 create-load-balancer 2 つ以上の AZ のサブネット、セキュリティグループ ロードバランサーの ARN
2 ターゲットグループ aws elbv2 create-target-group VPC ID、プロトコル、ポート ターゲットグループの ARN
3 ターゲット登録 aws elbv2 register-targets 2 の ARN、インスタンス ID (出力なし)
4 リスナー aws elbv2 create-listener 1 と 2 の ARN リスナーの ARN
5 ルール aws elbv2 create-rule 4 の ARN、転送先の ARN、優先度 ルールの ARN

確認・変更・削除でよく使うコマンドも並べておきます。

やりたいこと コマンド
ターゲットの状態を見る aws elbv2 describe-target-health --target-group-arn ARN
ルールを一覧する aws elbv2 describe-rules --listener-arn ARN
ヘルスチェックを変える aws elbv2 modify-target-group --target-group-arn ARN --health-check-path /healthz
ルールの条件を変える aws elbv2 modify-rule --rule-arn ARN --conditions …
ルールの優先度を変える aws elbv2 set-rule-priorities --rule-priorities RuleArn=ARN,Priority=5
ターゲットを外す aws elbv2 deregister-targets --target-group-arn ARN --targets Id=i-xxxx
削除する(この順で) delete-rule → delete-listener → delete-load-balancer → delete-target-group

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「ALBをAWS CLIで作成|ターゲットグループ・リスナー・ルール設定」

ALB を構成する 4 つの部品

ALB は「ロードバランサー本体」「リスナー」「ルール」「ターゲットグループ」の 4 つでできています。 リクエストは次の流れで振り分けられます。

flowchart LR
  C[クライアント] --> L[リスナー HTTP:80]
  L --> R1{ルール 優先度10<br>パスが /api/ で始まる}
  R1 -- 一致 --> T2[ターゲットグループ api-tg]
  R1 -- 不一致 --> D[デフォルトルール]
  D --> T1[ターゲットグループ web-tg]
  T1 --> I1[EC2 インスタンス 1]
  T1 --> I2[EC2 インスタンス 2]
  T2 --> I1
部品 役割
ロードバランサー 入口。サブネットとセキュリティグループに置かれ、DNS 名を持つ
リスナー 待ち受けるプロトコルとポート。どのルールにも合わないときのデフォルトアクションを持つ
ルール 条件(パス・ホストなど)とアクション(転送・リダイレクト・固定レスポンス)の組。優先度の数字が小さい順に評価される
ターゲットグループ 転送先の集まり。ヘルスチェックの設定もここに持つ

5 つのコマンドを通しで実行するスクリプト

前のコマンドの出力から --query '…Arn' --output text で ARN を取り出し、変数に入れて次へ渡します。 VPC・サブネット・セキュリティグループ・EC2 インスタンスは作成済みとし、冒頭の変数に自分の環境の値を入れます。

#!/bin/bash
# ALB 一式を作成する(VPC・サブネット・セキュリティグループ・EC2 は作成済みの前提)
set -euo pipefail

# ---- 自分の環境の値に置き換える ----
VPC_ID=vpc-xxxxxxxx
SUBNET_A=subnet-aaaaaaaa      # ap-northeast-1a
SUBNET_C=subnet-cccccccc      # ap-northeast-1c
SG_ID=sg-xxxxxxxx             # 80 番を許可したセキュリティグループ
INSTANCE_1=i-xxxxxxxxxxxxxxxxx
INSTANCE_2=i-yyyyyyyyyyyyyyyyy
# ------------------------------------
# vars.sh に同じ変数を書いておくと、そちらの値を使う
[ -f ./vars.sh ] && . ./vars.sh

# 1. ロードバランサー
ALB_ARN=$(aws elbv2 create-load-balancer \
  --name web-alb --type application --scheme internet-facing \
  --subnets "$SUBNET_A" "$SUBNET_C" --security-groups "$SG_ID" \
  --query 'LoadBalancers[0].LoadBalancerArn' --output text)
echo "ALB_ARN=$ALB_ARN"

# 2. ターゲットグループ(Web 用と API 用)
TG_ARN=$(aws elbv2 create-target-group \
  --name web-tg --protocol HTTP --port 80 --vpc-id "$VPC_ID" \
  --target-type instance \
  --health-check-path /health \
  --health-check-interval-seconds 15 --health-check-timeout-seconds 5 \
  --healthy-threshold-count 3 --unhealthy-threshold-count 2 \
  --matcher HttpCode=200-299 \
  --query 'TargetGroups[0].TargetGroupArn' --output text)
echo "TG_ARN=$TG_ARN"

API_TG_ARN=$(aws elbv2 create-target-group \
  --name api-tg --protocol HTTP --port 8080 --vpc-id "$VPC_ID" \
  --query 'TargetGroups[0].TargetGroupArn' --output text)
echo "API_TG_ARN=$API_TG_ARN"

# 3. ターゲット登録
aws elbv2 register-targets --target-group-arn "$TG_ARN" \
  --targets Id="$INSTANCE_1" Id="$INSTANCE_2"
aws elbv2 register-targets --target-group-arn "$API_TG_ARN" \
  --targets Id="$INSTANCE_1",Port=8080

# 4. リスナー(既定の転送先は web-tg)
LISTENER_ARN=$(aws elbv2 create-listener \
  --load-balancer-arn "$ALB_ARN" --protocol HTTP --port 80 \
  --default-actions Type=forward,TargetGroupArn="$TG_ARN" \
  --query 'Listeners[0].ListenerArn' --output text)
echo "LISTENER_ARN=$LISTENER_ARN"

# 5. ルール(/api/* は api-tg へ)
RULE_ARN=$(aws elbv2 create-rule \
  --listener-arn "$LISTENER_ARN" --priority 10 \
  --conditions Field=path-pattern,Values='/api/*' \
  --actions Type=forward,TargetGroupArn="$API_TG_ARN" \
  --query 'Rules[0].RuleArn' --output text)
echo "RULE_ARN=$RULE_ARN"

# 6. 確認
aws elbv2 describe-load-balancers --load-balancer-arns "$ALB_ARN" \
  --query 'LoadBalancers[0].[LoadBalancerName,Scheme,Type,State.Code]' --output text
aws elbv2 describe-rules --listener-arn "$LISTENER_ARN" \
  --query 'Rules[].[Priority,Conditions[0].Values[0],Actions[0].Type]' --output text

create-alb.sh として保存して実行した出力です。

bash create-alb.sh
ALB_ARN=arn:aws:elasticloadbalancing:ap-northeast-1:123456789012:loadbalancer/app/web-alb/b697ed833a1f4371
TG_ARN=arn:aws:elasticloadbalancing:ap-northeast-1:123456789012:targetgroup/web-tg/21804fae0e99e108
API_TG_ARN=arn:aws:elasticloadbalancing:ap-northeast-1:123456789012:targetgroup/api-tg/881bde866f9d157d
LISTENER_ARN=arn:aws:elasticloadbalancing:ap-northeast-1:123456789012:listener/app/web-alb/b697ed833a1f4371/69d2e7a15c787a23
RULE_ARN=arn:aws:elasticloadbalancing:ap-northeast-1:123456789012:listener-rule/app/web-alb/b697ed833a1f4371/69d2e7a15c787a23/45569358fab49318
web-alb internet-facing application active
10  /api/*  forward
default None    forward

ARN の形を見ると親子関係がわかります。 リスナーの ARN はロードバランサーの ID(b697ed833a1f4371)を含み、ルールの ARN はさらにリスナーの ID(69d2e7a15c787a23)を含みます。一方、ターゲットグループの ARN はロードバランサーの ID を含まず、独立した部品です。この違いが、あとで説明する削除の順番に関わります。

あとから ARN を取り直したいときは、名前から引けます。

ALB_ARN=$(aws elbv2 describe-load-balancers --names web-alb \
  --query 'LoadBalancers[0].LoadBalancerArn' --output text)
TG_ARN=$(aws elbv2 describe-target-groups --names web-tg \
  --query 'TargetGroups[0].TargetGroupArn' --output text)
LISTENER_ARN=$(aws elbv2 describe-listeners --load-balancer-arn $ALB_ARN \
  --query 'Listeners[0].ListenerArn' --output text)

各コマンドの出力を読む

スクリプトでは ARN だけを取り出しましたが、--query を外すと各コマンドは作成したものの全体を JSON で返します。順に見ていきます。ID は実行のたびに変わるため、このあとの出力例には ARN の末尾が異なるものがあります。

create-load-balancer の出力

aws elbv2 create-load-balancer \
  --name web-alb --type application --scheme internet-facing \
  --subnets $SUBNET_A $SUBNET_C --security-groups $SG_ID
{
    "LoadBalancers": [
        {
            "LoadBalancerArn": "arn:aws:elasticloadbalancing:ap-northeast-1:123456789012:loadbalancer/app/web-alb/9b51716b97e33a95",
            …(省略)…
            "LoadBalancerName": "web-alb",
            "Scheme": "internet-facing",
            "VpcId": "vpc-7b70ce50cc026ce8e",
            "State": {
                "Code": "provisioning"
            },
            "Type": "application",
            "AvailabilityZones": [
                {
                    "ZoneName": "ap-northeast-1a",
                    "SubnetId": "subnet-38887ef06a72f5ac0"
                },
                {
                    "ZoneName": "ap-northeast-1c",
                    "SubnetId": "subnet-fbc82fd9c64a99153"
                }
            ],
            "SecurityGroups": [
                "sg-b270fa51c2e3af047"
            ],
            "IpAddressType": "ipv4"
        }
    ]
}

作成直後の State.Code は provisioning で、準備が整うと active になります。 省略した部分には、アクセスに使う DNSName と、Route 53 のエイリアスレコードで使う CanonicalHostedZoneId も含まれます。

API リファレンス(CreateLoadBalancer)に書かれている主なオプションの決まりは次のとおりです。

オプション 既定値 決まり
--name (必須) 32 文字まで。英数字とハイフン。先頭・末尾のハイフンと、先頭の internal- は使えない
--type application application / network / gateway
--scheme internet-facing 外向けは internet-facing、VPC 内向けは internal
--subnets (必須) ALB は 2 つ以上のアベイラビリティーゾーンから、AZ ごとに 1 つずつ指定する
--ip-address-type ipv4 ALB は ipv4 / dualstack / dualstack-without-public-ipv4

スクリプトで作成完了を待ちたいときは、ウェイターを挟みます。

aws elbv2 wait load-balancer-available --load-balancer-arns $ALB_ARN

create-target-group の出力

aws elbv2 create-target-group \
  --name web-tg --protocol HTTP --port 80 --vpc-id $VPC_ID \
  --target-type instance \
  --health-check-path /health \
  --health-check-interval-seconds 15 --health-check-timeout-seconds 5 \
  --healthy-threshold-count 3 --unhealthy-threshold-count 2 \
  --matcher HttpCode=200-299
{
    "TargetGroups": [
        {
            "TargetGroupArn": "arn:aws:elasticloadbalancing:ap-northeast-1:123456789012:targetgroup/web-tg/a1354c422c67a6cd",
            "TargetGroupName": "web-tg",
            "Protocol": "HTTP",
            "Port": 80,
            "VpcId": "vpc-7b70ce50cc026ce8e",
            "HealthCheckProtocol": "HTTP",
            "HealthCheckPort": "traffic-port",
            "HealthCheckEnabled": true,
            "HealthCheckIntervalSeconds": 15,
            "HealthCheckTimeoutSeconds": 5,
            "HealthyThresholdCount": 3,
            "UnhealthyThresholdCount": 2,
            "HealthCheckPath": "/health",
            "Matcher": {
                "HttpCode": "200-299"
            },
            "TargetType": "instance",
            "ProtocolVersion": "HTTP1",
            "IpAddressType": "ipv4"
        }
    ]
}

ヘルスチェックのオプションを何も付けずに作った api-tg は、次の値になりました。

aws elbv2 create-target-group --name api-tg --protocol HTTP --port 8080 --vpc-id $VPC_ID \
  --query 'TargetGroups[0].{Arn:TargetGroupArn,Interval:HealthCheckIntervalSeconds,Timeout:HealthCheckTimeoutSeconds,Healthy:HealthyThresholdCount,Unhealthy:UnhealthyThresholdCount,Path:HealthCheckPath,Port:HealthCheckPort,Protocol:HealthCheckProtocol,Matcher:Matcher.HttpCode,TargetType:TargetType}'
{
    "Arn": "arn:aws:elasticloadbalancing:ap-northeast-1:123456789012:targetgroup/api-tg/d9c7f31344e3e354",
    "Interval": 30,
    "Timeout": 5,
    "Healthy": 5,
    "Unhealthy": 2,
    "Path": "/",
    "Port": "traffic-port",
    "Protocol": "HTTP",
    "Matcher": "200",
    "TargetType": "instance"
}

ヘルスチェックのオプション早見表

ヘルスチェックは「何秒おきに、どのパスへ、何回続けて成功・不成功なら状態を切り替えるか」を決める設定です。 ALB のユーザーガイド(ターゲットグループのヘルスチェック)に載っている既定値と範囲です。ターゲットタイプが instance または ip の場合の値を示します。

オプション 意味 既定値 範囲
--health-check-protocol チェックに使うプロトコル HTTP HTTP / HTTPS
--health-check-port チェック先のポート traffic-port(転送と同じポート) 1〜65535
--health-check-path チェック先のパス / 有効な URI
--health-check-interval-seconds チェックの間隔 30 秒 5〜300 秒
--health-check-timeout-seconds 応答を待つ時間 5 秒 2〜120 秒
--healthy-threshold-count 正常と判定するまでの連続成功回数 5 2〜10
--unhealthy-threshold-count 異常と判定するまでの連続不成功回数 2 2〜10
--matcher HttpCode=… 成功とみなす HTTP ステータス 200 200〜499。200-299 のように範囲でも書ける

既定値のままだと、新しいターゲットが正常と判定されるまでに「30 秒 × 5 回」ほどかかります。切り替えを早めたいときは、間隔としきい値を小さくします。 上のスクリプトでは 15 秒 × 3 回にしています。アプリケーションに /health のような軽い応答を返すパスを用意し、それをチェック先にすると判定が安定します。

register-targets と describe-target-health

register-targets は成功しても何も出力しません。登録できたかは describe-target-health で確認します。ポートを省くとターゲットグループのポートが使われ、Id=…,Port=8080 と書くとターゲットごとに変えられます。

aws elbv2 register-targets --target-group-arn $TG_ARN \
  --targets Id=$INSTANCE_1 Id=$INSTANCE_2

aws elbv2 describe-target-health --target-group-arn $TG_ARN \
  --query 'TargetHealthDescriptions[].[Target.Id,Target.Port,TargetHealth.State]' \
  --output table

ヘルスチェックを通ったあとの表示は次のとおりです。

------------------------------------------
|          DescribeTargetHealth          |
+----------------------+-----+-----------+
|  i-aeaa250e75ee61017 |  80 |  healthy  |
|  i-99063769549952cd2 |  80 |  healthy  |
+----------------------+-----+-----------+

State に出る値の意味は、ユーザーガイドで次のように説明されています。

State 意味
initial 登録の処理中、または最初のヘルスチェックの途中
healthy ヘルスチェックに通っている
unhealthy ヘルスチェックに応答しない、または通っていない
unused ターゲットグループがどのリスナーからも使われていない、AZ が有効でない、インスタンスが停止している、など
draining 登録解除の途中で、処理中の接続が終わるのを待っている
unavailable ターゲットグループのヘルスチェックが無効になっている

unused のままなら、リスナーやルールからそのターゲットグループがまだ参照されていない可能性があります。リスナーを作ってからもう一度確認します。

create-listener の出力

aws elbv2 create-listener \
  --load-balancer-arn $ALB_ARN --protocol HTTP --port 80 \
  --default-actions Type=forward,TargetGroupArn=$TG_ARN
{
    "Listeners": [
        {
            "ListenerArn": "arn:aws:elasticloadbalancing:ap-northeast-1:123456789012:listener/app/web-alb/9b51716b97e33a95/5f4e8e254e1df153",
            "LoadBalancerArn": "arn:aws:elasticloadbalancing:ap-northeast-1:123456789012:loadbalancer/app/web-alb/9b51716b97e33a95",
            "Port": 80,
            "Protocol": "HTTP",
            …(省略)…
            "DefaultActions": [
                {
                    "Type": "forward",
                    "TargetGroupArn": "arn:aws:elasticloadbalancing:ap-northeast-1:123456789012:targetgroup/web-tg/a1354c422c67a6cd"
                }
            ]
        }
    ]
}

--default-actions が、どのルールにも合わなかったリクエストの行き先です。リスナーを作ると、このデフォルトアクションを持つ「デフォルトルール」が 1 つ自動でできます。

HTTPS で待ち受けるリスナーは、AWS CLI リファレンス(create-listener)の例にあるとおり、証明書の ARN とセキュリティポリシーを加えます。

aws elbv2 create-listener \
  --load-balancer-arn $ALB_ARN \
  --protocol HTTPS --port 443 \
  --certificates CertificateArn=arn:aws:acm:ap-northeast-1:123456789012:certificate/3dcb0a41-bd72-4774-9ad9-756919c40557 \
  --ssl-policy ELBSecurityPolicy-2016-08 \
  --default-actions Type=forward,TargetGroupArn=$TG_ARN

--certificates には証明書を 1 つだけ指定します。

create-rule で条件とアクションを書く

ルールは「条件(Conditions)に合ったら、アクション(Actions)を行う」という 1 行です。 優先度(--priority)は 1〜50000 の数字で、小さい順に評価され、最初に合ったルールのアクションが行われます。どれにも合わなければデフォルトルールが使われます。

短い書き方(パス条件で転送)

aws elbv2 create-rule \
  --listener-arn $LISTENER_ARN --priority 10 \
  --conditions Field=path-pattern,Values='/api/*' \
  --actions Type=forward,TargetGroupArn=$API_TG_ARN
{
    "Rules": [
        {
            "RuleArn": "arn:aws:elasticloadbalancing:ap-northeast-1:123456789012:listener-rule/app/web-alb/9b51716b97e33a95/5f4e8e254e1df153/8d724ff699559cce",
            "Priority": "10",
            "Conditions": [
                {
                    "Field": "path-pattern",
                    "Values": [
                        "/api/*"
                    ]
                }
            ],
            "Actions": [
                {
                    "Type": "forward",
                    "TargetGroupArn": "arn:aws:elasticloadbalancing:ap-northeast-1:123456789012:targetgroup/api-tg/d9c7f31344e3e354"
                }
            ],
            "IsDefault": false
        }
    ]
}

Values の * をシェルに展開させないよう、値は引用符で囲みます。

リダイレクトのルール(JSON ファイル)

アクションが複雑になったら JSON ファイルに書き、file:// で渡します。old.example.com へのアクセスを https://www.example.com の同じパスへ 301 で移す例です(rule-redirect.json)。

[
  {
    "Type": "redirect",
    "RedirectConfig": {
      "Protocol": "HTTPS",
      "Port": "443",
      "Host": "www.example.com",
      "Path": "/#{path}",
      "Query": "#{query}",
      "StatusCode": "HTTP_301"
    }
  }
]
aws elbv2 create-rule \
  --listener-arn $LISTENER_ARN --priority 20 \
  --conditions Field=host-header,Values='old.example.com' \
  --actions file://rule-redirect.json
{
    "Rules": [
        {
            "RuleArn": "arn:aws:elasticloadbalancing:ap-northeast-1:123456789012:listener-rule/app/web-alb/b697ed833a1f4371/69d2e7a15c787a23/2353be5818b7155b",
            "Priority": "20",
            "Conditions": [
                {
                    "Field": "host-header",
                    "Values": [
                        "old.example.com"
                    ]
                }
            ],
            "Actions": [
                {
                    "Type": "redirect",
                    "RedirectConfig": {
                        "Protocol": "HTTPS",
                        "Port": "443",
                        "Host": "www.example.com",
                        "Path": "/#{path}",
                        "Query": "#{query}",
                        "StatusCode": "HTTP_301"
                    }
                }
            ],
            "IsDefault": false
        }
    ]
}

#{path} や #{query} は、元のリクエストの値をそのまま引き継ぐための書き方です。ほかに #{protocol} #{host} #{port} があります。StatusCode は HTTP_301(恒久的)か HTTP_302(一時的)です。

固定レスポンスのルール

ターゲットに転送せず、ALB 自身が決まった応答を返します。メンテナンス中の案内などに使えます(rule-fixed.json)。

[
  {
    "Type": "fixed-response",
    "FixedResponseConfig": {
      "StatusCode": "503",
      "ContentType": "text/plain",
      "MessageBody": "Maintenance"
    }
  }
]
aws elbv2 create-rule \
  --listener-arn $LISTENER_ARN --priority 30 \
  --conditions Field=path-pattern,Values='/maintenance*' \
  --actions file://rule-fixed.json --query 'Rules[0].Actions'
[
    {
        "Type": "fixed-response",
        "FixedResponseConfig": {
            "MessageBody": "Maintenance",
            "StatusCode": "503",
            "ContentType": "text/plain"
        }
    }
]

複数の条件を組み合わせる

1 つのルールには条件を複数並べられます。API リファレンス(CreateRule)では「ルールの条件が満たされたときに、そのアクションが行われる」と説明されています。また、1 つの条件の中に値を複数書いた場合は、どれか 1 つに合えばその条件は満たされます(ユーザーガイドの条件タイプの説明より)。ホスト・パス・HTTP メソッドを組み合わせた例です(cond-multi.json)。

[
  { "Field": "host-header", "HostHeaderConfig": { "Values": ["admin.example.com"] } },
  { "Field": "path-pattern", "PathPatternConfig": { "Values": ["/reports/*", "/export/*"] } },
  { "Field": "http-request-method", "HttpRequestMethodConfig": { "Values": ["GET", "HEAD"] } }
]
aws elbv2 create-rule \
  --listener-arn $LISTENER_ARN --priority 40 \
  --conditions file://cond-multi.json \
  --actions Type=forward,TargetGroupArn=$API_TG_ARN \
  --query 'Rules[0].[Priority,length(Conditions)]' --output text
40  3

HTTP ヘッダー・クエリ文字列・送信元 IP の条件も同じ形で書けます(cond-extra.json)。

[
  { "Field": "http-header", "HttpHeaderConfig": { "HttpHeaderName": "X-Client", "Values": ["mobile*"] } },
  { "Field": "query-string", "QueryStringConfig": { "Values": [ { "Key": "version", "Value": "v2" } ] } },
  { "Field": "source-ip", "SourceIpConfig": { "Values": ["203.0.113.0/24"] } }
]
aws elbv2 create-rule \
  --listener-arn $LISTENER_ARN --priority 50 \
  --conditions file://cond-extra.json \
  --actions Type=forward,TargetGroupArn=$API_TG_ARN \
  --query 'Rules[0].Conditions[].Field'
[
    "http-header",
    "query-string",
    "source-ip"
]

重みをつけて 2 つのターゲットグループへ転送する

ForwardConfig を使うと、リクエストを割合で分けられます。新しい版を少しずつ試すときに使えます(fwd-weighted.json。ARN は自分のものに置き換えます)。

[
  {
    "Type": "forward",
    "ForwardConfig": {
      "TargetGroups": [
        { "TargetGroupArn": "arn:aws:elasticloadbalancing:ap-northeast-1:123456789012:targetgroup/web-tg/21804fae0e99e108", "Weight": 90 },
        { "TargetGroupArn": "arn:aws:elasticloadbalancing:ap-northeast-1:123456789012:targetgroup/api-tg/881bde866f9d157d", "Weight": 10 }
      ]
    }
  }
]
aws elbv2 create-rule \
  --listener-arn $LISTENER_ARN --priority 60 \
  --conditions Field=path-pattern,Values='/beta/*' \
  --actions file://fwd-weighted.json \
  --query 'Rules[0].Actions[0].ForwardConfig.TargetGroups[].Weight'
[
    90,
    10
]

Weight は 0〜999 の範囲で指定します。

条件とアクションの早見表

ALB のユーザーガイド(ルールの条件タイプ、アクションタイプ)の記載をまとめます。

条件の Field 何を見るか 大文字・小文字 ワイルドカード
path-pattern URL のパス(クエリ文字列は含まない) 区別する *(0 文字以上)と ?(1 文字)
host-header Host ヘッダー 区別しない * と ?
http-header 任意の HTTP ヘッダー 名前・値とも区別しない 値にだけ使える
http-request-method HTTP メソッド 区別する 使えない(完全一致)
query-string クエリ文字列のキーと値 区別しない * と ?
source-ip 送信元 IP アドレス ― 使えない(CIDR 形式で書く)
上限 値
1 つのルールに書ける条件 5 つまで
1 つの条件に書ける値 3 つまで
1 つのルールで使えるワイルドカード 5 個まで
同じ Field を複数書けるもの http-header と query-string
アクションの Type 動作 設定を書く場所
forward ターゲットグループへ転送する TargetGroupArn または ForwardConfig
redirect 別の URL へリダイレクトする RedirectConfig
fixed-response 決まった応答を返す(ステータスは 2XX・4XX・5XX) FixedResponseConfig
authenticate-oidc OIDC 準拠の ID プロバイダーで認証する(HTTPS リスナー) ―
authenticate-cognito Amazon Cognito で認証する(HTTPS リスナー) ―

ルールを一覧・変更する

ここまでに作ったルールを優先度順に一覧します。

aws elbv2 describe-rules --listener-arn $LISTENER_ARN \
  --query 'Rules[].[Priority,Conditions[0].Field,Actions[0].Type,IsDefault]' --output table
--------------------------------------------------------
|                     DescribeRules                    |
+---------+----------------+------------------+--------+
|  10     |  path-pattern  |  forward         |  False |
|  20     |  host-header   |  redirect        |  False |
|  30     |  path-pattern  |  fixed-response  |  False |
|  40     |  host-header   |  forward         |  False |
|  50     |  http-header   |  forward         |  False |
|  60     |  path-pattern  |  forward         |  False |
|  default|  None          |  forward         |  True  |
+---------+----------------+------------------+--------+

優先度の変更は set-rule-priorities、条件やアクションの変更は modify-rule です。

RULE_ARN=$(aws elbv2 describe-rules --listener-arn $LISTENER_ARN \
  --query "Rules[?Priority=='10'].RuleArn" --output text)

aws elbv2 set-rule-priorities --rule-priorities RuleArn=$RULE_ARN,Priority=5 \
  --query 'Rules[].Priority' --output text

aws elbv2 modify-rule --rule-arn $RULE_ARN \
  --conditions Field=path-pattern,Values='/api/v1/*' \
  --query 'Rules[0].Conditions[0].Values'
5
[
    "/api/v1/*"
]

Priority は文字列で返るので、--query の比較は '10' と引用符つきで書きます。

ヘルスチェックの設定は modify-target-group であとから変えられます。

aws elbv2 modify-target-group --target-group-arn $TG_ARN \
  --health-check-path /healthz --health-check-interval-seconds 10 \
  --query 'TargetGroups[0].[HealthCheckPath,HealthCheckIntervalSeconds]' --output text
/healthz    10

作成時に出やすいエラーと直し方

エラー文のかっこ内(エラーコード)を見ると、どの部品の指定が合っていないかがわかります。 今回の確認環境で実際に出たものを並べます。

操作 エラー文 直し方
使用中の優先度で create-rule (PriorityInUse) … The specified priority is in use. 空いている番号にする。または set-rule-priorities で既存をずらす
同じ名前で設定の違うターゲットグループを作成 (DuplicateTargetGroupName) … A target group with the specified name already exists. 名前を変える。既存を使うなら describe-target-groups --names で ARN を取る
タイムアウトを間隔以上にした (ValidationError) … Health check timeout '10' must be smaller than the interval '5' タイムアウトを間隔より短くする
しきい値を 1 にした Parameter validation failed: Invalid value for parameter HealthyThresholdCount, value: 1, valid min value: 2 2〜10 の範囲にする
間隔を 3 秒にした Parameter validation failed: Invalid value for parameter HealthCheckIntervalSeconds, value: 3, valid min value: 5 5〜300 の範囲にする
名前にアンダースコアを使った (ValidationError) … Target group name 'bad_tg' can only contain characters that are alphanumeric characters or hyphens(-) 英数字とハイフンだけにする
条件の Field を path と書いた (ValidationError) … Condition field 'path' must be one of '[path-pattern,host-header,http-header,http-request-method,query-string,source-ip]' path-pattern と書く
--priority を付け忘れた aws: error: the following arguments are required: --priority 優先度を指定する
無い名前で describe-load-balancers (LoadBalancerNotFound) … The specified load balancer does not exist. 名前とリージョンを確認する
ターゲットグループの ARN が違う (TargetGroupNotFound) … Target group '…' not found 変数の中身を echo で確認する
リスナーの ARN が違う (ListenerNotFound) … The specified listener does not exist. describe-listeners で取り直す

「Parameter validation failed」で始まるものは、AWS へ送る前に CLI が範囲を確かめて止めたものです。API リファレンスには、このほかに DuplicateLoadBalancerName(同じ名前のロードバランサーがある)、SubnetNotFound、InvalidSecurityGroup、TooManyRules(ルール数の上限)などが挙げられています。

削除の順番と ResourceInUse

ターゲットグループは、リスナーやルールから参照されている間は削除できません。 作った直後の状態で delete-target-group を実行すると、次のエラーで止まります。

aws elbv2 delete-target-group --target-group-arn $TG_ARN
An error occurred (ResourceInUse) when calling the DeleteTargetGroup operation: The target group 'arn:aws:elasticloadbalancing:ap-northeast-1:123456789012:targetgroup/web-tg/21804fae0e99e108' is currently in use by a listener or a rule

ルールからだけ参照されている api-tg も同じです。

An error occurred (ResourceInUse) when calling the DeleteTargetGroup operation: The target group 'arn:aws:elasticloadbalancing:ap-northeast-1:123456789012:targetgroup/api-tg/881bde866f9d157d' is currently in use by a listener or a rule

参照している側(ルール・リスナー)を先に消し、参照されている側(ターゲットグループ)を最後に消すのが正しい順番です。

順 削除するもの コマンド 理由
1 ルール aws elbv2 delete-rule --rule-arn ARN ターゲットグループを参照している。デフォルトルールは対象外
2 リスナー aws elbv2 delete-listener --listener-arn ARN デフォルトアクションがターゲットグループを参照している
3 ロードバランサー aws elbv2 delete-load-balancer --load-balancer-arn ARN リスナーが無くなった本体を消す
4 ターゲットグループ aws elbv2 delete-target-group --target-group-arn ARN どこからも参照されなくなってから消す

ALB のユーザーガイドによると、ターゲットグループを削除しても、登録されていた EC2 インスタンスには影響しません。インスタンスが不要なら別に停止・終了します。

一式を削除するスクリプト

create-alb.sh で作ったものを、上の順番で削除するスクリプトです。

#!/bin/bash
# create-alb.sh で作った一式を、依存の少ない順に削除する
set -euo pipefail

ALB_ARN=$(aws elbv2 describe-load-balancers --names web-alb \
  --query 'LoadBalancers[0].LoadBalancerArn' --output text)

# 1. ルール → 2. リスナー
for LISTENER_ARN in $(aws elbv2 describe-listeners --load-balancer-arn "$ALB_ARN" \
    --query 'Listeners[].ListenerArn' --output text); do
  for RULE_ARN in $(aws elbv2 describe-rules --listener-arn "$LISTENER_ARN" \
      --query 'Rules[?!IsDefault].RuleArn' --output text); do
    aws elbv2 delete-rule --rule-arn "$RULE_ARN"
    echo "deleted rule: ${RULE_ARN##*/}"
  done
  aws elbv2 delete-listener --listener-arn "$LISTENER_ARN"
  echo "deleted listener: ${LISTENER_ARN##*/}"
done

# 3. ロードバランサー(削除完了まで待つ)
aws elbv2 delete-load-balancer --load-balancer-arn "$ALB_ARN"
aws elbv2 wait load-balancers-deleted --load-balancer-arns "$ALB_ARN"
echo "deleted load balancer: web-alb"

# 4. ターゲットグループ
for NAME in web-tg api-tg; do
  TG_ARN=$(aws elbv2 describe-target-groups --names "$NAME" \
    --query 'TargetGroups[0].TargetGroupArn' --output text)
  aws elbv2 delete-target-group --target-group-arn "$TG_ARN"
  echo "deleted target group: $NAME"
done
bash delete-alb.sh
deleted rule: 45569358fab49318
deleted rule: 2353be5818b7155b
deleted rule: a7268d6f871914c0
deleted rule: 44e2a1159e9d33ce
deleted rule: 5402f6acceb19978
deleted rule: de55bb87524f71f7
deleted listener: 69d2e7a15c787a23
deleted load balancer: web-alb
deleted target group: web-tg
deleted target group: api-tg

Rules[?!IsDefault] でデフォルトルール以外だけを選んでいます。デフォルトルールはリスナーと一緒に消えます。最後にロードバランサーが残っていないことを確認します。

aws elbv2 describe-load-balancers --query 'LoadBalancers[].LoadBalancerName'
[]

ターゲットだけを外す

ALB は残したまま、特定のインスタンスだけを振り分け先から外すときは deregister-targets を使います。

aws elbv2 deregister-targets --target-group-arn $TG_ARN --targets Id=$INSTANCE_2

aws elbv2 describe-target-health --target-group-arn $TG_ARN \
  --query 'TargetHealthDescriptions[].[Target.Id,TargetHealth.State]' --output text
i-aeaa250e75ee61017 healthy

登録解除の待ち時間は、ターゲットグループの属性 deregistration_delay.timeout_seconds で決まります。確認すると 300 秒でした。

aws elbv2 describe-target-group-attributes --target-group-arn $TG_ARN \
  --query "Attributes[?Key=='deregistration_delay.timeout_seconds']"
[
    {
        "Key": "deregistration_delay.timeout_seconds",
        "Value": "300"
    }
]

よくある質問

Q. ターゲットグループとロードバランサーは、どちらを先に作ればよいですか? A. どちらが先でも作れます。2 つを結びつけるのはリスナー(とルール)なので、リスナーを作る時点で両方の ARN がそろっていれば大丈夫です。この記事では、エラーが出たときに原因を追いやすいよう、入口から順に作っています。

Q. describe-target-health が unused のままです。 A. そのターゲットグループが、まだどのリスナーやルールからも参照されていないときに出る状態です。create-listener か create-rule で転送先に指定してから、もう一度確認します。

Q. ルールの優先度はどう決めればよいですか? A. 数字が小さいほど先に評価されます。あとから間に差し込めるよう、10・20・30 のように間隔をあけて振ると扱いやすくなります。条件が狭いルール(特定のホストとパスの組み合わせなど)を小さい数字にし、広い条件を大きい数字にするのが基本です。

Q. HTTP を HTTPS に移すルールはどう書きますか? A. HTTP:80 のリスナーのデフォルトアクションを redirect にします。RedirectConfig の Protocol を HTTPS、Port を 443、StatusCode を HTTP_301 にし、Host・Path・Query は #{host}・/#{path}・#{query} で元の値を引き継ぎます。

まとめ

  • 作る順番は「ロードバランサー → ターゲットグループ → ターゲット登録 → リスナー → ルール」
  • 前の出力の ARN を --query '…Arn' --output text で変数に受け取ると、通しで実行できる
  • ヘルスチェックは既定で 30 秒間隔・5 回成功で正常。切り替えを早めるなら間隔としきい値を小さくする
  • ルールは優先度の小さい順に評価され、条件は 1 ルール 5 つまで。1 つの条件に書いた複数の値は、どれか 1 つに合えばよい
  • アクションは forward・redirect・fixed-response が基本で、複雑なものは JSON ファイルで渡す
  • ResourceInUse はターゲットグループがまだ参照されている合図。ルール → リスナー → ロードバランサー → ターゲットグループの順に消す
  • PriorityInUse や DuplicateTargetGroupName は名前・番号の重なり。エラーコードを見て対象を直す

参考・出典

  • Elastic Load Balancing API リファレンス:CreateLoadBalancer、CreateTargetGroup、CreateRule
  • Application Load Balancer ユーザーガイド:ターゲットグループのヘルスチェック、ルールの条件タイプ、ルールのアクションタイプ、ターゲットグループの削除
  • AWS CLI コマンドリファレンス:elbv2 create-listener

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「ALBをAWS CLIで作成|ターゲットグループ・リスナー・ルール設定」

株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。

WE ARE HIRING

RJCで一緒に開発しながら、
成長を楽しみませんか?

RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!

  • 127日年間休日
  • 12時間平均残業時間
  • 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!

ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。

ABOUT RJC RJCがどんな会社か知る 考え方、研修、働き方、福利厚生、社員の前職まで。RJCのことが丸わかり! RJC丸わかりページへ JOB DESCRIPTION 仕事内容・待遇を見てみる 仕事内容、給与・待遇、選考の流れ。経験者も未経験も!応募前に知りたいこと、まとめました! 募集要項を見る ENTRY エントリーする エントリーは1〜2分・履歴書不要です。まずは話を聞いてみたい、という方でも歓迎です! エントリーフォームへ

RJCで一緒に開発しながら、 成長を楽しみませんか?