ablog

不器用で落着きのない技術者のメモ

AWS Glue から別アカウントの Aurora PostgreSQL に接続する

AWS Glue で VPC Peering 経由で別アカウントの Aurora PostgreSQL に接続した手順をメモ。

前提

手順

  • マネジメントコンソールから [AWS Glue] - [データベース] - [接続] を選択。
  • [接続の追加] をクリック、以下の通り設定。
    • タイプ: JDBC
    • JDBC URL: jdbc:postgresql://apg117.cluster-******.ap-northeast-1.rds.amazonaws.com:5432/postgres
    • VPC ID: vpc-b6****d1 ★ VPC Peering を設定した VPC を選択
    • サブネット: subnet-12****5b
    • セキュリティグループ: sg-0d*************45
    • ユーザー名: awsuser ★ DBユーザー名
    • パスワード: ********* ★ DB パスワード

NATゲートウェイの作成に失敗する

事象

  • NATゲートウェイを作成すると、Failed となり、状態メッセージに "Network vpc-****** has no Internet gateway attached" と表示される。

f:id:yohei-a:20210131160336p:plain
f:id:yohei-a:20210131161416p:plain

原因

NAT ゲートウェイの作成に失敗する

問題

NAT ゲートウェイを作成すると、Failed 状態になります。

原因

NAT ゲートウェイの作成時にエラーが発生しました。返った状態メッセージは、エラーの理由を表します。

ソリューション

エラーメッセージを表示するには、Amazon VPC コンソールに移動し、[NAT ゲートウェイ] を選択します。NAT ゲートウェイを選択し、詳細ペインの [ステータスメッセージ] フィールドでエラーメッセージを確認します。
次の表は、Amazon VPC コンソールに示される失敗の考えられる原因のリストです。示された修復手順のいずれかを適用したら、NAT ゲートウェイの作成を再度試すことができます。
(中略)

表示されるエラー 原因 ソリューション
ネットワーク vpc-xxxxxxxx にインターネットゲートウェイがアタッチされていません NAT ゲートウェイは、インターネットゲートウェイがアタッチされた VPC で作成する必要があります。 インターネットゲートウェイを作成して VPC にアタッチします。詳細については、「インターネットゲートウェイの作成とアタッチ」を参照してください。

(以下略)

NAT ゲートウェイのトラブルシューティング - Amazon Virtual Private Cloud

解決策

08. ネットワーク設定

VPC とサブネット
# VPC/サブネット名 CIDR Availability Zone
1 design-cookbook-dev-vpc 172.16.0.0/16 ap-northeast-1
2 design-cookbook-public-subnet01 172.24.1.0/24 ap-northeast-1a
3 design-cookbook-public-subnet02 172.24.2.0/24 ap-northeast-1c
4 design-cookbook-private-subnet01 172.24.11.0/24 ap-northeast-1a
5 design-cookbook-private-subnet02 172.24.12.0/24 ap-northeast-1c
6 design-cookbook-protected-subnet01 172.24.21.0/24 ap-northeast-1a
7 design-cookbook-protected-subnet02 172.24.22.0/24 ap-northeast-1c
  • インターネットゲートウェイ "design-cookbook-igw" を作成
  • VPC "design-cookbook-dev-vpc" にアタッチ
  • "design-cookbook-public-subnet01" のルートテーブルに以下を追加
送信先 ターゲット
0.0.0.0/0 igw-*******
ルートテーブル
  • design-cookbook-public-rtb
送信先 ターゲット
172.16.0.0/16 local
0.0.0.0/0 igw-******
  • design-cookbook-private01-rtb
送信先 ターゲット
172.16.0.0/16 local
0.0.0.0/0 design-cookbook-private-subnet01-natgw
  • design-cookbook-private02-rtb
送信先 ターゲット
172.16.0.0/16 local
0.0.0.0/0 design-cookbook-private-subnet02-natgw
  • design-cookbook-procted-rtb
送信先 ターゲット
172.16.0.0/16 local
NATゲートウェイ
# NATゲートウェイ サブネット名
1 design-cookbook-private-subnet01-natgw design-cookbook-private-subnet01
2 design-cookbook-private-subnet02-natgw design-cookbook-private-subnet02

AWS CLI で VPC エンドポイント経由でアクセスする

事象

原因

  • グローバルエンドポイント(sts.amazonaws.com)が使用されているため。
    • AWS CLI v1 はデフォルトでグローバルエンドポイントが利用される。
    • AWS CLI v2 はデフォルトでリージョンのエンドポイント(sts.ap-northeast-1.amazonaws.com など)が利用される。

解決策

AWS CLI v1 の場合
  • ~/.aws/config で設定する
[profile switchrole]
role_arn = arn:aws:iam::111111111111:role/SwitchRole
source_profile = default
region=ap-northeast-1 ★ココ
output=json
sts_regional_endpoints=regional ★ココ
$ export AWS_STS_REGIONAL_ENDPOINTS=regional
  • --endpoint-url オプションで指定する
aws sts get-caller-identity --endpoint-url https://sts.ap-northeast-1.amazonaws.com
AWS SDK(boto3)の場合
  • STS のクライアントオブジェクト生成時に region_name と endpoint_url に実行するリージョン名とエンドポイントを指定する。例えば、東京リージョンの場合は、"boto3.client('sts')" を "boto3.client('sts', region_name='ap-northeast-1', endpoint_url='https://sts.ap-northeast-1.amazonaws.com')" とする。
# region_name と endpoint_url を指定する
sts_connection = boto3.client('sts', region_name='ap-northeast-1', endpoint_url='https://sts.ap-northeast-1.amazonaws.com') 

補足

  • S3 や Code Commit などで Assume Role 方式でクロスアカウントアクセスする場合も STS にアクセスできる必要がある。
  • AWS CLI でうまく行かない場合は、--debug オプションをつけてデバッグログを出力する。以下はグローバルエンドポイントにアクセスしてタイムアウトしている。
aws s3 cp test.txt s3://arn:aws:s3:ap-northeast-1:123456789012:accesspoint/foo/bar/ --acl bucket-owner-full-control --profile account1 --debug

(中略)

2021-07-29 17:29:45,221 - Thread-3 - botocore.endpoint - DEBUG - Making request for OperationModel(name=PutObject) with params: {'body': <s3transfer.utils.ReadFileChunk object at 0x7f3a4777f110>, 'url': u'https://s3.amazonaws.com/foo/bar/test.txt', 'headers': {'Expect': '100-continue', u'Content-Type': 'text/plain', u'x-amz-acl': 'bucket-owner-full-control', 'User-Agent': 'aws-cli/1.18.147 Python/2.7.18 Linux/4.14.232-177.418.amzn2.x86_64 botocore/1.18.6'}, 'context': {'auth_type': None, 'client_region': 'us-east-1★', 'signing': {'bucket': u'arn:aws:s3:ap-northeast-1:123456789012:accesspoint/foo'}, 'has_streaming_input': True, 'client_config': <botocore.config.Config object at 0x7f3a47896410>, 's3_accesspoint': {'region': u'ap-northeast-1', 'account': u'123456789012', 'partition': u'aws', 'name': u'foo'}}, 'query_string': {}, 'url_path': u'/foo/bar/test.txt', 'method': u'PUT'}

参考

AWS_STS_REGIONAL_ENDPOINTS

AWS CLI クライアントが AWS Security Token Service (AWS STS) と通信するために使用する AWS サービスエンドポイントを AWS CLI がどのように決定するかを指定します。

  • AWS CLI バージョン 1 のデフォルト値はlegacyです。
  • AWS CLI バージョン 2 のデフォルト値はregionalです。

次の 2 つの値のいずれかを指定できます。

  • legacy - 次の AWS リージョンに対してグローバル STS エンドポイントsts.amazonaws.comを使用します。ap-northeast-1、ap-south-1、ap-southeast-1、ap-southeast-2、aws-global、ca-central-1、eu-central-1、eu-north-1、eu-west-1、eu-west-2、eu-west-3、sa-east-1、us-east-1、us-east-2、us-west-1、および us-west-2。他のすべてのリージョンでは、それぞれのリージョンエンドポイントが自動的に使用されます。
  • regional - AWS CLI は、現在設定されているリージョンに対して AWS STS エンドポイントを常に使用します。例えば、クライアントが us-west-2 を使用するように設定されている場合、AWS STS へのすべてのコールは、グローバル sts.amazonaws.com エンドポイントではなく、リージョナルエンドポイント sts.us-west-2.amazonaws.com に対して行われます。この設定が有効なときにグローバルエンドポイントにリクエストを送信するには、リージョンを aws-global に設定します。
AWS CLI を設定する環境変数 - AWS Command Line Interface

Python でタイムスタンプのタイムゾーンを変換する

Python でタイムスタンプのタイムゾーンを変換するコード例。例えば、CloudTrail のタイムゾーンUTC から JST に変換するといった場合。以下のコードは AWS Lambda でも追加モジュール不要で実行可能。

  • コード
import datetime
import dateutil.parser
def lambda_handler(event, context):
    awstime = '2021-01-28T00:22:50Z'
    JST = datetime.timezone(datetime.timedelta(hours=+9), 'JST')
    jst_datetime = dateutil.parser.parse(awstime).astimezone(JST)
    print(jst_datetime)
  • 実行結果
START RequestId: fed8f625-c8c3-4a8f-8d1c-32412acceeba Version: $LATEST
2021-01-28 09:22:50+09:00

MariaDB Connector/J のロギング設定

As Per Lundberg already stated, logging is possible since version 1.5.0, see here.

To activate it, I added &log=true to my database URL. However, this was not sufficient. As explained here, the following steps are also needed:

First, we need to add some dependencies:

<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>[1.4.0,1.7.25]</version>
</dependency>
<dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-classic</artifactId>
    <version>1.2.3</version>
</dependency>
|xml|<
Then we need to configure logback like in the given example:
>|xml|
<?xml version="1.0" encoding="UTF-8"?>
<configuration>

    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n</pattern>
        </encoder>
    </appender>

    <logger name="org.mariadb.jdbc" level="trace" additivity="false">
        <appender-ref ref="STDOUT"/>
    </logger>

    <root level="error">
        <appender-ref ref="STDOUT"/>
    </root>

</configuration>

The "trace" log level gives a lot of information, so you might want to use another one. The currently supported log levels are: trace, debug, info, warn or error

java - MariaDB JDBC Client Logging - Stack Overflow

MariaDB Connector/J で Aurora MySQL に接続すると INFORMATION_SCHEMA.REPLICA_HOST_STATUS からエンドポイントを取得する?

Amazon Aurora DB クラスターエンドポイントは、DNS レコードの更新を自動的に伝播しますが、処理は即座に行われるわけではありません。これにより、データベースで発生したイベントへの応答が遅れる可能性があり、イベントがアプリケーションによって処理される可能性があります。スマートドライバは、ほぼリアルタイムの INFORMATION_SCHEMA.REPLICA_HOST_STATUS メタデータテーブルを通じて DB クラスターのトポグラフィーを使用します。これにより、接続を適切なロールにルーティングし、既存のレプリカ間で負荷分散を行うのに役立ちます。MariaDB コネクタ/J は、Aurora MySQLをネイティブサポートしているサードパーティーのスマートドライバの例です。

Aurora DB クラスターがフェイルオーバーした後の読み取り専用エラーのトラブルシューティング

In versions before 1.5.1, cluster endpoint use was discouraged, since when a failover occurs, this cluster endpoint can point for a limited time to a host that isn't the current master any more. The old recommendation was to list all specific end-points. This kind of url string will still work, but now, recommended url string has to use only cluster endpoint.

Driver will automatically discover master and slaves of this cluster from current cluster end-point during connection time. This permits adding new replicas to the cluster instance which will be discovered without changing driver configuration.

Failover and High availability with MariaDB Connector/J - MariaDB Knowledge Base
  /**
   * Retrieves the information necessary to add a new endpoint. Calls the methods that retrieves the
   * instance identifiers and sets urlParser accordingly.
   *
   * @param protocol current protocol connected to
   * @throws SQLException if connection error occur
   */
  public void retrieveAllEndpointsAndSet(Protocol protocol) throws SQLException {
    // For a given cluster, same port for all endpoints and same end host address
    if (clusterDnsSuffix != null) {
      List<String> endpoints = getCurrentEndpointIdentifiers(protocol);
      setUrlParserFromEndpoints(endpoints, protocol.getPort());
    }
  }

/**
   * Retrieves all endpoints of a cluster from the appropriate database table.
   *
   * @param protocol current protocol connected to
   * @return instance endpoints of the cluster
   * @throws SQLException if connection error occur
   */
  private List<String> getCurrentEndpointIdentifiers(Protocol protocol) throws SQLException {
    List<String> endpoints = new ArrayList<>();
    try {
      proxy.lock.lock();
      try {
        // Deleted instance may remain in db for 24 hours so ignoring instances that have had no
        // change
        // for 3 minutes
        Results results = new Results();
        protocol.executeQuery(
            false,
            results,
            "select server_id, session_id from information_schema.replica_host_status " ★
                + "where last_update_timestamp > now() - INTERVAL 3 MINUTE");
        results.commandEnd();
        ResultSet resultSet = results.getResultSet();

        while (resultSet.next()) {
          endpoints.add(resultSet.getString(1) + "." + clusterDnsSuffix);
        }

        // randomize order for distributed load-balancing
        Collections.shuffle(endpoints);
  • INFORMATION_SCHEMA.REPLICA_HOST_STATUS
$ mysql -h aurora-mysql-5712-cluster.cluster-*******.ap-northeast-1.rds.amazonaws.com -u awsuser  -p
mysql> select * from INFORMATION_SCHEMA.REPLICA_HOST_STATUS\G
*************************** 1. row ***************************
                             SERVER_ID: aurora-mysql-5712
                            SESSION_ID: 5aead66f-1174-4f49-9431-2a1e5bce7020
                                  IOPS: 0
                              READ_IOS: 0
                      PENDING_READ_IOS: 0
                                   CPU: 6.324110507965088
                           DURABLE_LSN: 18446744073709551363
                            ACTIVE_LSN: 0
                  LAST_TRANSPORT_ERROR: 0
                  LAST_ERROR_TIMESTAMP: 1970-01-01 00:00:01.000000
                 LAST_UPDATE_TIMESTAMP: 2021-01-27 06:14:51.447303
  MASTER_SLAVE_LATENCY_IN_MICROSECONDS: 0
           REPLICA_LAG_IN_MILLISECONDS: 20.229000091552734
    LOG_STREAM_SPEED_IN_KiB_PER_SECOND: 2.102880738213399
            LOG_BUFFER_SEQUENCE_NUMBER: 7509
                            IS_CURRENT: 0
               OLDEST_READ_VIEW_TRX_ID: 2439276
                  OLDEST_READ_VIEW_LSN: 124843572
                  HIGHEST_LSN_RECEIVED: 124843574
                    CURRENT_READ_POINT: 124843572
CURRENT_REPLAY_LATENCY_IN_MICROSECONDS: 382690
AVERAGE_REPLAY_LATENCY_IN_MICROSECONDS: 466222
    MAX_REPLAY_LATENCY_IN_MICROSECONDS: 1026895
*************************** 2. row ***************************
                             SERVER_ID: aurora-mysql-5712-ap-northeast-1c
                            SESSION_ID: MASTER_SESSION_ID
                                  IOPS: 0
                              READ_IOS: 0
                      PENDING_READ_IOS: 0
                                   CPU: 4.332129955291748
                           DURABLE_LSN: 124843582
                            ACTIVE_LSN: 0
                  LAST_TRANSPORT_ERROR: 0
                  LAST_ERROR_TIMESTAMP: 1970-01-01 00:00:01.000000
                 LAST_UPDATE_TIMESTAMP: 2021-01-27 06:14:51.426614
  MASTER_SLAVE_LATENCY_IN_MICROSECONDS: 0
           REPLICA_LAG_IN_MILLISECONDS: 0
    LOG_STREAM_SPEED_IN_KiB_PER_SECOND: 2.102880738213399
            LOG_BUFFER_SEQUENCE_NUMBER: 7508
                            IS_CURRENT: 0
               OLDEST_READ_VIEW_TRX_ID: 0
                  OLDEST_READ_VIEW_LSN: 0
                  HIGHEST_LSN_RECEIVED: 0
                    CURRENT_READ_POINT: 0
CURRENT_REPLAY_LATENCY_IN_MICROSECONDS: 0
AVERAGE_REPLAY_LATENCY_IN_MICROSECONDS: 0
    MAX_REPLAY_LATENCY_IN_MICROSECONDS: 0
2 rows in set (0.03 sec)

mysql>