ホームページ  >  記事  >  Java  >  Amazon SQS を使用した Spring Boot コンシューマ アプリケーションの構築: クラウド開発キット (CDK) を使用したインフラストラクチャのセットアップ

Amazon SQS を使用した Spring Boot コンシューマ アプリケーションの構築: クラウド開発キット (CDK) を使用したインフラストラクチャのセットアップ

Susan Sarandon
Susan Sarandonオリジナル
2024-10-07 22:08:30563ブラウズ
017 日目 - 100 日間 AWSIaCDevops チャレンジ

今日は、100 日間のコードチャレンジ シリーズで、Springboot で開発されたマイクロサービスを Amazon SQS を使用して分離する方法を説明します。

Amazon SQS とは何ですか?

Amazon SQS (Simple Queue Service) は、アプリケーションが sendyg によって通信し、メッセージをキューに保存および受信するのを支援するクラウド サービスです。これは、消費者が処理する準備ができるまで保存される待機列のようなものです。これにより、システムが過剰に制御されるのを防ぎ、メッセージが失われないようにします。

Springboot アプリケーションを使用して SQS メッセージを消費する

SQS キューからの各メッセージを処理する Spring Boot アプリを作成して、SQS メッセージを使用する方法を示します。 CDK (Java) を使用して構築されたインフラストラクチャには以下が含まれます:

  • Spring Boot アプリが実行される EC2 インスタンスをホストするための、パブリック サブネット を持つ VPC
  • EC2 インスタンスがインターネットにアクセスして依存関係をダウンロードするための インターネット ゲートウェイ
  • メッセージストレージ用の SQS キュー および デッドレターキュー
  • SpringBoot アプリをホストするための EC2 インスタンス
  • EC2 インスタンスが SQS キューからメッセージを取得できるようにする IAM ロール (非常に重要)。

インフラストラクチャを作成する

CDK (Java) を使用して必要なインフラストラクチャをセットアップする

Building a Spring Boot Consumer Application with Amazon SQS: Setup Infrastructure Using Cloud Development Kit (CDK)

VPC および Subne インターネット ゲートウェイ


public class NetworkContruct extends Construct {
  private final IVpc vpc;
  public NetworkContruct(Construct scope, String id, StackProps props) {
    super(scope, id);
    this.vpc =
        new Vpc(
            this,
            "VpcResource",
            VpcProps.builder()
                .vpcName("my-vpc")
                .enableDnsHostnames(true)
                .enableDnsSupport(true)
                .createInternetGateway(true)
                .ipProtocol(IpProtocol.IPV4_ONLY)
                .ipAddresses(IpAddresses.cidr("10.0.0.1/16"))
                .maxAzs(1)
                .subnetConfiguration(
                    List.of(
                        SubnetConfiguration.builder()
                            .name("Public-Subnet")
                            .mapPublicIpOnLaunch(true)
                            .subnetType(SubnetType.PUBLIC)
                            .build()))
                .build());
  }
  public IVpc getVpc() {
    return vpc;
  }
}


この cdk コンストラクトは以下を作成します:
?? my-vpc という名前の VPC と DNS ホスト名を有効にします。
?? Public-Subnet という名前のパブリック サブネット。リソースがパブリック IP を接続できるようにします (パブリック IP が設定されている場合)。
??インターネット トラフィックを有効にするインターネット ゲートウェイ。

SQS キューとデッドレター キュー


public class QueueConstruct extends Construct {
  private final IQueue queue;
  public QueueConstruct(Construct scope, String id, IVpc vpc, StackProps props) {
    super(scope, id);
    IQueue dlq =
        new Queue(
            this,
            "DeadLetterQueue",
            QueueProps.builder()
                .deliveryDelay(Duration.millis(0))
                .retentionPeriod(Duration.days(10))
                .queueName("my-queue-dlq")
                .build());
    DeadLetterQueue deadLetterQueue = DeadLetterQueue.builder()
        .queue(dlq)
        .maxReceiveCount(32)
        .build();

    this.queue =
        new Queue(
            this,
            "SQSQueueResource",
            QueueProps.builder()
                .queueName("my-queue")
                .retentionPeriod(Duration.minutes(15))
                .visibilityTimeout(Duration.seconds(90))
                .deadLetterQueue(deadLetterQueue)
                .build());
  }

  public IQueue getQueue() {
    return queue;
  }
}


上記の CDK コンストラクトは次のリソースを作成します:

  • Spring Boot アプリで使用される my-queue という名前のキュー。
  • my-queue-dlq という名前の DeadLetter キュー は、失敗したメッセージをキャプチャし、メイン キューをブロックすることなく、後で分析して修正できるようにします。

Spring Boot アプリケーションをホストするための EC2 インスタンス


// ComputerProps.java
public record ComputerProps(IVpc vpc, String sqsQueueArn) {}

// ComputerConstruct.java
public class ComputerConstruct extends Construct {
  private final IInstance computer;
  public ComputerConstruct(
      Construct scope, String id, ComputerProps computerProps, StackProps props) {
    super(scope, id);
    SecurityGroup securityGroup =
        new SecurityGroup(
            this,
            "WebserverSGResource",
            SecurityGroupProps.builder()
                .allowAllOutbound(true)
                .securityGroupName("Webserver-security-group")
                .disableInlineRules(true)
                .vpc(computerProps.vpc())
                .description("Allow trafic from/to webserver instance")
                .build());

    securityGroup.addIngressRule(Peer.anyIpv4(), Port.SSH, "Allow ssh traffic");
    securityGroup.addIngressRule(Peer.anyIpv4(), Port.tcp(8089), "Allow traffic from 8089 port");

    KeyPair keyPair =
        new KeyPair(
            this,
            "KeyPairResource",
            KeyPairProps.builder()
                .keyPairName("ws-keypair")
                .account(Objects.requireNonNull(props.getEnv()).getAccount())
                .type(KeyPairType.RSA)
                .format(KeyPairFormat.PEM)
                .build());

    new CfnOutput(
        this, "KeyPairId", CfnOutputProps.builder().value(keyPair.getKeyPairId()).build());

    Instance ec2Instance =
        new Instance(
            this,
            "WebServerInstanceResource",
            InstanceProps.builder()
                .securityGroup(securityGroup)
                .keyPair(keyPair)
                .instanceName("Webserver-Instance")
                .machineImage(
                    MachineImage.lookup(
                        LookupMachineImageProps.builder()
                            .name("*ubuntu*")
                            .filters(
                                Map.ofEntries(
                                    Map.entry("image-id", List.of("ami-0e86e20dae9224db8")),
                                    Map.entry("architecture", List.of("x86_64"))))
                            .windows(false)
                            .build()))
                .vpc(computerProps.vpc())
                .role(buildInstanceRole(computerProps))
                .instanceType(InstanceType.of(InstanceClass.T2, InstanceSize.MICRO))
                .associatePublicIpAddress(true)
                .blockDevices(
                    List.of(
                        BlockDevice.builder()
                            .mappingEnabled(true)
                            .deviceName("/dev/sda1")
                            .volume(
                                BlockDeviceVolume.ebs(
                                    10,
                                    EbsDeviceOptions.builder()
                                        .deleteOnTermination(true)
                                        .volumeType(EbsDeviceVolumeType.GP3)
                                        .build()))
                            .build()))
                .userDataCausesReplacement(true)
                .vpcSubnets(SubnetSelection.builder().subnetType(SubnetType.PUBLIC).build())
                .build());

    UserData userData = UserData.forLinux();
    userData.addCommands(readFile("./webserver-startup.sh"));

    ec2Instance.addUserData(userData.render());

    this.computer = ec2Instance;
  }

  public IInstance getComputer() {
    return computer;
  }

  private String readFile(String filename) {

    InputStream scriptFileStream = getClass().getClassLoader().getResourceAsStream(filename);

    try {
      assert scriptFileStream != null;
      try (InputStreamReader isr = new InputStreamReader(scriptFileStream, StandardCharsets.UTF_8);
          BufferedReader br = new BufferedReader(isr)) {
        StringBuilder content = new StringBuilder();
        String line;
        while ((line = br.readLine()) != null) {
          content.append(line).append("\n");
        }
        return content.toString();
      }
    } catch (IOException e) {
      throw new RuntimeException(e.getMessage());
    }
  }

  private IRole buildInstanceRole(ComputerProps props) {
    return new Role(
        this,
        "WebserverInstanceRoleResource",
        RoleProps.builder()
            .roleName("webserver-role")
            .assumedBy(new ServicePrincipal("ec2.amazonaws.com"))
            .path("/")
            .inlinePolicies(
                Map.ofEntries(
                    Map.entry(
                        "sqs",
                        new PolicyDocument(
                            PolicyDocumentProps.builder()
                                .assignSids(true)
                                .statements(
                                    List.of(
                                        new PolicyStatement(
                                            PolicyStatementProps.builder()
                                                .effect(Effect.ALLOW)
                                                .actions(
                                                    List.of(
                                                        "sqs:DeleteMessage",
                                                        "sqs:ReceiveMessage",
                                                        "sqs:SendMessage",
                                                        "sqs:GetQueueAttributes",
                                                        "sqs:GetQueueUrl"))
                                                .resources(List.of(props.sqsQueueArn()))
                                                .build())))
                                .build()))))
            .build());
  }
}


上記の CDK コンストラクトは次のリソースを作成します:

  • SSH 接続のポート 22 での受信トラフィックを許可し、アプリケーション接続ポートである ポート 8089 での受信トラフィックを許可する Webserver-security-group という名前のセキュリティ グループ。
  • SSH 経由でアプリホストに接続するために使用される ws-keypair という名前のキー ペア。 CDK を使用してインフラストラクチャを構築しているため、デプロイ後に秘密キー (PEM ファイル) をダウンロードする必要がある場合は、Cloudformation または CDK スタックの作成後に秘密キー ファイル PEM を取得する方法に関する私の以前の記事を参照してください。
  • Webserver-Instance という名前の Ec2 インスタンス。
  • webserver-role という名前の Ec2 インスタンスの IAM ロール。これにより、Ec2 インスタンスでホストされている Spring Boot アプリケーションが Amazon SQS キュー (作成済み) との接続を確立し、アクション (メッセージの削除、メッセージの受信、メッセージの送信) を実行できるようになります。 、キュー属性を取得し、キュー URL を取得します。

スタックを作成する


// MyStack.java
public class MyStack extends Stack {
  public MyStack(final Construct scope, final String id, final StackProps props) {
    super(scope, id, props);
    IVpc vpc = new NetworkContruct(this, "NetworkResource", props).getVpc();
    IQueue queue = new QueueConstruct(this, "QueueResource", vpc, props).getQueue();
    IInstance webserver =
        new ComputerConstruct(
                this, "ComputerResource", new ComputerProps(vpc, queue.getQueueArn()), props)
            .getComputer();
  }
}

// Day17App.java
public class Day017App {
  public static void main(final String[] args) {
    App app = new App();
    new MyStack(app,"Day017Stack",
        StackProps.builder()
                .env(
                    Environment.builder()
                        .account(System.getenv("CDK_DEFAULT_ACCOUNT"))
                        .region(System.getenv("CDK_DEFAULT_REGION"))
                        .build())
                .build());
    app.synth();
  }
}


SpringBoot コンシューマ アプリケーションの作成

物事をシンプルにして、生活が複雑になるのを避けるために、Spring Cloud AWS Docs[↗]

を使用します。

Spring Cloud AWS は、Spring Framework および Spring Boot アプリケーションでの AWS マネージド サービスの使用を簡素化します。これは、よく知られた Spring イディオムと API を使用して、AWS が提供するサービスと対話する便利な方法を提供します。

プロジェクトで SQS サービスを構成するには、構成クラスに次の Bean を追加します。


@Configuration
public class ApplicationConfiguration {
    @Bean
    public AwsRegionProvider customRegionProvider() {
        return new InstanceProfileRegionProvider();
    }
    @Bean
    public AwsCredentialsProvider customInstanceCredProvider() {
        return  InstanceProfileCredentialsProvider.builder()
                .build();
    }
}


そして、すべての新しいメッセージをキャプチャし、その内容を出力するリスナーです。


@Slf4j
@Component
public class ExampleSQSConsumer {
    @SqsListener(queueNames = { "my-queue" }) // ??
    public void listen(String payload) {
        log.info("*******************  SQS Payload ***************");
        log.info("Message Content: {}", payload);
        log.info("Received At: {}", Date.from(Instant.now()));
        log.info("************************************************");
    }
}


完全なプロジェクトは私の GitHub リポジトリにあります[↗]

導入

⚠️⚠️ デプロイメント コマンドを実行する前に、ホスト マシンに Java がインストールされていることを確認してください。このインフラストラクチャを構築するために、MacO で Java 21 を使用しました。

任意の場所でターミナルを開き、次のコマンドを実行します:


<p>git clone https://github.com/nivekalara237/100DaysTerraformAWSDevops.git<br>
cd 100DaysTerraformAWSDevops/day_017<br>
cdk bootstrap --profile cdk-user<br>
cdk deploy --profile cdk-user Day017Stack</p>




結果

Building a Spring Boot Consumer Application with Amazon SQS: Setup Infrastructure Using Cloud Development Kit (CDK)


完全なソース コードは GitHub リポジトリで見つけることができます↗

以上がAmazon SQS を使用した Spring Boot コンシューマ アプリケーションの構築: クラウド開発キット (CDK) を使用したインフラストラクチャのセットアップの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。