GoでS3に格納したファイルにバッチ処理するDockerイメージを作りたい。
S3に格納されたファイルがあって、バッチ処理するためのdockerコンテナが作りたかったのでやって見ました。
言語はGolangです。
バッチ処理のやりたいこと
今回はS3に格納されたファイルをダウンロードしてきて、違う名前で再アップロードするバッチ処理です。
特に、AWS Batch(AWS Batch とは - AWS Batch)のようなサービスでHPCを行う想定で作っています。
AWS Batchだと、処理対象のデータはS3かEFSになるので、元データの落とし方と処理結果の格納方法さえ分かれば後はなんとかなるだろうという寸法です。
バッチ処理のコード
基本的にはGo SDKの公式ドキュメント(https://docs.aws.amazon.com/sdk-for-go/api/service/s3/)を見るとそのまま書いているので、愚直にやっていきます。
サンプルコードはこちらです。
github.com
セッションの確立
まず、AWSとのセッションを作成します。
session.NewSession()で普通にセッションを作ると、環境変数を読みに行ってくれます。
credentialsの認証情報でもいけるはずですが、未検証です。
// Region, AccesskeyID & SeacretAccessKey is specified in environment.
sess, err := session.NewSession()
session.NewSessionWithOptions()で認証情報などをハードコードすることも可能です。
Resionなんかはそんなに変わらないのでハードコードしちゃっても良いと思いますが、アクセスキーとシークレットアクセスキーを書き込むのは非推奨です。
// Specifying Region. AccesskeyID & SeacretAccessKey is specified in environment. sess, err := session.NewSessionWithOptions(session.Options{ Config: aws.Config{ Region: aws.String("ap-northeast-1"), }, })
ダウンロード
s3manager.NewDownloader()でダウンロード用のインスタンスが生成できます。
// Create a downloader with the session and default options downloader := s3manager.NewDownloader(sess) // Create a file to write the S3 Object contents to. downloadContent, err := os.Create(localTmpFile) if err != nil { fmt.Println(err) return } // Write the contents of S3 Object to the file n, err := downloader.Download(downloadContent, &s3.GetObjectInput{ Bucket: aws.String(bucketName), Key: aws.String(downloadTarget), }) if err != nil { fmt.Println(err) return } fmt.Printf("file downloaded, %d bytes\n", n)
アップロード
s3manager.NewUploader()でアップロード用のインスタンスが生成できます。
// Create an uploader with the session and default options uploader := s3manager.NewUploader(sess) uploadContent, err := os.Open(localTmpFile) if err != nil { fmt.Println(err) return } // Upload the file to S3. result, err := uploader.Upload(&s3manager.UploadInput{ Bucket: aws.String(bucketName), Key: aws.String(uploadTaget), Body: uploadContent, }) if err != nil { fmt.Println(err) return } fmt.Printf("file uploaded to, %s\n", result.Location)
Dockerfile
SDKの認証情報は、ENV で設定すると読み込んでくれました。
~/.aws/credentialsでもいけるはずですがAWSサービス内で環境変数として渡してしまうユースケースの方が多いと思うので、dockerfileのENVで渡してしまうか、docker run の-eオプションで指定するのが良いのかなと思います(私感)。
FROM golang:1.12 ENV PKG_PATH /go/src/ ENV GO111MODULE on WORKDIR $PKG_PATH RUN go mod download COPY ./ $PKG_PATH RUN go install . FROM golang:1.12 COPY --from=0 /go/bin /go/bin/ ENV AWS_ACCESS_KEY_ID=アクセスキーID ENV AWS_SECRET_ACCESS_KEY=シークレットアクセスキー ENV AWS_REGION=リージョン ENTRYPOINT ["/go/bin/main"]