継続は力なり

タイトル通り定期的な更新を心掛けるブログです。

RDS ログを S3 にアップロードする Python スクリプトを Docker 上で実行する

タダです.

前回の記事で RDS ログをダウンロードする Python スクリプトを作った記事を書きました.今回の記事はで Python スクリプトに S3 アップロードする処理を追加したものを ECS 上で動かすためにローカルで Docker イメージにし,ローカル実行をしてみるまでの過程を備忘録にまとめます.

sadayoshi-tada.hatenablog.com

Python スクリプトに S3 アップロードの処理を追加する

前回の記事で書いたコードに S3 アップロード処理を追加してみたコードが次のものになります.

rds_donwload_to_s3_upload.py

import boto3
from botocore.awsrequest import AWSRequest
import botocore.auth as auth
import requests
import tempfile

region = 'ap-northeast-1'
session = boto3.session.Session()
rds_endpoint = 'rds.' + region + '.amazonaws.com'
rds = boto3.client('rds')
parser = argparse.ArgumentParser()
parser.add_argument('aurora_cluster_name', type=str)
parser.add_argument('target_s3_bucket', type=str)
args = parser.parse_args()
aurora_cluster_name = args.aurora_cluster_name
target_s3_bucket = args.target_s3_bucket
s3 = boto3.resource('s3')
bucket = s3.Bucket(target_s3_bucket)

def get_db_instance_identifiers(aurora_cluster_name: str) -> list[str]:
    target_db_instance_identifiers = []
    response = rds.describe_db_clusters(DBClusterIdentifier=aurora_cluster_name)
    members = response['DBClusters'][0]['DBClusterMembers']
    for member in members:
        target_db_instance_identifiers.append(member['DBInstanceIdentifier'])
    return target_db_instance_identifiers

def get_log_file_names_from_aurora(db_instance_identifier: str) -> list[str]:
    download_log_files = []
    describe_db_log_files_pagenator = rds.get_paginator('describe_db_log_files')
    describe_db_log_files_page_iterator = describe_db_log_files_pagenator.paginate(DBInstanceIdentifier = db_instance_identifier)
    for describe_db_log_files_page in describe_db_log_files_page_iterator:
        for describe_db_log_file in describe_db_log_files_page['DescribeDBLogFiles']:
            download_log_files.append(describe_db_log_file['LogFileName'])

def download_rds_logfile(db_instance_identifier:str, log_file_name:str, region:str, rds_endpoint:str) -> str:
    download_complete_logfile_url = 'https://' + rds_endpoint + '/v13/downloadCompleteLogFile/' + db_instance_identifier + '/' + log_file_name
    credential = session.get_credentials()
    awsreq = AWSRequest(method = 'GET', url = download_complete_logfile_url)
    sigv4auth = auth.SigV4Auth(credentials, 'rds', region)
    sigv4auth.add_auth(awsreq)
    res = requests.get(download_complete_logfile_url, stream=True, headers={
            'Authorization': awsreq.headers['Authorization'],
            'X-Amz-Date': awsreq.context['timestamp'],
            'X-Amz-Security-Token': credential.token
    })
    log_file_content = res.text
    res.close
    return log_file_content

def main():
    db_instance_identifiers = get_db_instance_identifiers(aurora_cluster_name)
    for db_instance_identifier in db_instance_identifiers:
        log_file_names = get_log_file_names_from_aurora(db_instance_identifier)
        for log_file_name in log_file_names:
            with download_rds_logfile(db_instance_identifier, log_file_name, region, rds_endpoint) as log_file_content:
                with tempfile.NamedTemporaryFile(dir=".",mode='w') as fp:
                    fp.write(log_file_content)
                    fp.seek(0)
                    bucket.upload_file(tmp.name, f"{db_instance_identifier}/{log_file_name}")
 
if __name__ == '__main__':
    main()

Python スクリプトを動かすための Dockerfile 準備

Python スクリプトができたので,Dockefile をマルチステージビルドで作ります.なお,ライブラリ管理には poetry を使う前提で作っています.

# syntax=docker/dockerfile:1
FROM python:3.11-slim-buster AS builder
ENV POETRY_HOME=/opt/poetry
ENV PATH="$POETRY_HOME/bin:$PATH"
RUN apt-get update && \
    apt-get install --no-install-recommends -y curl && \
    apt-get clean
RUN curl -sSL https://install.python-poetry.org/ | python3 -
WORKDIR /tmp
COPY ./pyproject.toml ./poetry.lock ./
RUN poetry config virtualenvs.create false && \
    poetry install

FROM python:3.11-slim-buster
WORKDIR /app
COPY --from=builder /usr/local/lib/python3.11/site-packages /usr/local/lib/python3.11/site-packages
COPY ./rds_donwload_to_s3_upload.py .

ENTRYPOINT [ "python3", "rds_donwload_to_s3_upload.py" ]

上記の Dockerfile をビルドすると自分の手元で 210MB くらいのサイズになりました.

$ docker build -t rds-log-to-s3-upload .
$ docker images
REPOSITORY                TAG               IMAGE ID       CREATED         SIZE
rds-log-to-s3-upload  latest            ced5cc959045   16 hours ago    210MB

Docker を起動してスクリプトを実行してみる

ビルドしたイメージでスクリプトを実行してみたところ S3 バケットにログが入っていることを確認できました.

$ docker run --rm -t -e AWS_DEFAULT_REGION="ap-northeast-1" -e AWS_ACCESS_KEY_ID="hoge" -e AWS_SECRET_ACCESS_KEY="hogehoge" rds-log-to-s3-upload:latest [Aurora クラスター名] [S3 バケット名]

まとめ

前回の記事で Python スクリプトを Docker で実行するためにやったことをまとめました.次回は ECS でタスク実行するために必要なことをまとめていきます.