🕹️

EC2 AutoScalingGroupにElasticIPを自動でアタッチする.sh

2024/01/30に公開

そもそもIPを固定化しようとするな!

元も子もない

例えばスケーリングのグループ外に存在するインスタンスから固定の接続情報が欲しい時など、AutoScalingを実装する際にAutoScalingGroupにスケールアウトされたインスタンスに対してElasticIPを自動的に付与する仕組みが欲しくなる時があるかも知れません。

こういう時は #shellのパワー系ソリューション が有効ですよね

良し悪しはさておき、とりあえず作ってみて楽しかったので忘れないように備忘録として記事に残しておきたいと思います。ご参考頂く際は注意してください(検証用途で利用してください)。

結論

以下のシェルを設置して実行
https://github.com/shakevo/eip-scalable-attach/blob/master/eip_scalable_attach.sh

参考記事:https://dev.classmethod.jp/articles/choose-eip-from-addresspool/

解説

    # スクリプトの配置されているディレクトリパス
    WORK_DIR=$(cd $(dirname $0);pwd)
    # 実行ファイル,ログファイルの絶対パス指定
    WORK_EXEC_FILE="${WORK_DIR}/eip_scalable_attach.sh"
    WORK_LOG_FILE="${WORK_DIR}/eip_scalable_attach.log"

シェルのファイルを置いている場所に依存するのがあまり好きではないので、ファイルを置いている場所を起点に実行されるようにします。
このシェルではeip_scalable_attach.shを実行すると、その実行ログeip_scalable_attach.logを生成させたい為、その2ファイルのファイルパスを指定します(ファイル名は任意に変更頂いて差し支えありません)。

    # プールしているEIPのAllocationIDを全て指定する(スペース区切り)
    # eipalloc-0xxxxxxxx(Name:Pooling_EIP_01, 3.114.xxx.xxx)
    # eipalloc-0yyyyyyyy(Name:Pooling_EIP_02, 52.192.yyy.yyy)
    eip_alloc_ids="eipalloc-0xxxxxxxx eipalloc-0yyyyyyyy"

このシェルでアタッチする為に予めプールしておいたElasticIPの"eipalloc"から始まるAllocationIDを指定します。Management Console等でAllocationIDを確認の上、eip_alloc_idsに指定してください。
AllocationIDはスペース区切りで複数指定できるので、スケールアウトの最大数*2程度指定をしてください。確保が難しい場合はそれ以下に抑えてもいいですが、急激なスケールイン/スケールアウトが発生した際にアタッチに失敗する可能性があります。
検証用途で利用を推奨する原因はここで、大量のスケールアウトの可能性がある場合そもそもこの方法を試すことは不向きです。かつグローバルなIPv4の枯渇問題もある為、大量のElasticIPを確保すべきではありません。

    # インスタンスID取得
    instance_id=$(curl -s http://169.254.169.254/latest/meta-data/instance-id)
    # リージョン取得
    region=$(curl -s http://169.254.169.254/latest/meta-data/placement/availability-zone | sed -e 's/.$//')

curlで、AWSメタデータを取得します。

    # AWS CLIの環境変数AWS_DEFAULT_REGIONを設定する
    export AWS_DEFAULT_REGION=${region}

メタで取得したリージョン設定を、AWS CLIの環境変数AWS_DEFAULT_REGIONに指定します。

    # 割り当て可能なEIPを取得(インスタンスIDが割り当てされていないEIP)
    available_alloc_id=$(aws ec2 describe-addresses --allocation-ids ${eip_alloc_ids} | jq -r '[.Addresses[] | select(.InstanceId == null)][0] | .AllocationId')

スクリプトを実行するEC2にEC2ロールの割当てと、jqのインストールが必要となる1行です。
プール対象のElasticIPの中から、インスタンスIDがまだ未割当のElasticIP AllocationIDのみを取得します。最終的には、ここで取得したAllocationIDのみを対象にアタッチを実施します。

    # 日付を書き込み
    now=$(date "+%Y/%m/%d %H:%M:%S")
    echo "--${now}--" >> ${WORK_LOG_FILE} 2>&1
    # 割り当てEIPを書き込み
    echo ${available_alloc_id} >> ${WORK_LOG_FILE} 2>&1

スクリプトの実行ログを出力します。
ログには割当てを行ったElasticIPのAllocationIDと、成功/失敗が追記されていきます。

    aws ec2 associate-address --instance-id ${instance_id} --allocation-id ${available_alloc_id} --no-allow-reassociation >> ${WORK_LOG_FILE} 2>&1

プールされていたElasticIPをアタッチします。
意図せずアタッチ処理が衝突されるのを防ぐ為に--no-allow-reassociationオプションを指定しています。--no-allow-reassociationを指定することで、ElasticIPが既に付与されている場合は上書きアタッチせずtrueを戻り値として返すようになります。

補足 -- スクリプトのサービス化

このスクリプトを実行する場合、サービス化して自動実行されるような起動設定とします。

vi /etc/systemd/system/eip_scalable_attach.service

[Unit]
After=network-online.target

[Service]
User=root
ExecStart={シェルスクリプトの絶対パス}

[Install]
WantedBy=multi-user.target
systemctl enable eip_scalable_attach.service
systemctl is-enabled eip_scalable_attach.service

補足 -- 検証用途にすべき理由と反省点

  • グローバルIP(ElasticIP)を必要不可欠数以上に確保するのは良くない
  • ElasticIPの確保可能数に依存してしまう
  • そもそもAutoScalingGroup内のインスタンスへ、極力静的に情報を指定すべきではない

Discussion