📑

gokitで作成したアプリケーションをdocker-composeでデプロイする(AWS Fargate)

2023/05/17に公開

gokitで作成したアプリケーションをdocker-composeでデプロイする(AWS Fargate)

こんにちは!情報科学専門学校のモノづくりサークル、MakeITのkentyです!
今回は、

  • gokitについて
  • AWS Fargateを用いて簡単にAWS上にデプロイする方法

についてお話ししたいと思います!

(公式ドキュメントはこちら)

前提知識

今回の記事は、

  • golangについて基本文法程度の知識
  • Docker,Docker Composeに対する基礎的な知識
  • AWSについて簡単なサービスの理解(IAM/ECS)

があれば大丈夫です!

簡単な解説

gokitとは?

Go言語でマイクロサービスを構築するためのツールキットです。
Go kitは、分散システムの開発に必要な一般的なパターン、設計原則、コンポーネントを提供し、マイクロサービスの構築を簡素化することができます。

ただ、今回はお試しで触ったということもあり、tutorialの一番最初でできる部分である、
https://gokit.io/examples/stringsvc.html
について行います。

AWS Fargateとは?

AWS Fargateは、Amazon Web Services(AWS)のコンテナオーケストレーションサービスであり、マネージドなコンテナ実行環境を提供します。Fargateを使用することで、コンテナを実行するためのインフラストラクチャの管理やセキュリティの設定をすべて自動で行ってくれます。

解説

今回は、自分が作成したこちらのリポジトリをもとに解説していきます。
https://github.com/kentyisapen/stringsvc

各ファイルの解説

├── .air.toml // airの設定ファイル
├── Dockerfile.dev //開発環境用のdocker file. airによって自動リロード
├── Dockerfile.prod //本番環境用のdocker file. buildして実行
├── docker-compose.yml //開発環境用のcompose.yml volume,buildが指定してある
├── go.mod //いつもの
├── go.sum //いつもの
├── main.go //アプリケーション
├── .env //環境変数
└── production.yml // 開発環境用のcompose.yml ECRでのimageを指定

順を追って説明します。

main.go

今回のアプリケーションです。
内容そのものは、リクエストボディでもらった文字列を大文字にしたり、その文字数をカウントする、という簡素なものです。
他にも、gokit特有の物事(Endpoint,Middleware,Transportなど)があるのですが、それらについては自分がまだ完全に理解しきれていないというのと、すでに良い記事がありましたのでこちらをご紹介させてください。

https://medium.com/@m_kikuchi/go-kitのサンプル読んでみた-cd043a8f0ae5

Dockerfile.dev, Dockerfile.prod

それぞれ開発環境用、本番環境用のDockerfileです。
開発環境用では、airを使うことによってホットリロードを行っています。
本番環境ではホットリロードをする必要はなく、そもそもbuildしたものを実行すればよいのでこのような中身になっております。

docker-compose.yml, production.yml

どちらもほぼ最小といってよいと思います。
開発環境用のdocker-composeの方はvolumeを指定することによってマウントしています。
逆に、productionの方はECRに予めpushしたimageを使用しています。
こちらのアカウントIDはenvのほうで指定します。

.env

今回指定する必要があるのは、今後デプロイに使用するAWS IAMユーザーのアカウントIDのみです。

AWS_ACCOUNT_ID=XXXXXXXXXXX

デプロイしてみる

アカウント周り

まず、デプロイを行うためには以下2つのアカウントが必要です。

  • Dockerアカウント
  • AWSアカウント(IAMユーザー)

Dockerアカウントに関しては、Docker Hubよりユーザー登録を行ってください。
特に設定はいらず、ユーザー名とパスワードだけ覚えておいてください。

AWSアカウントに関してはIAMユーザーを作成し、以下の権限を与えてください。
今回、リージョンはap-southeast-1に作成します。

  • AmazonEC2ContainerRegistryFullAccess
  • AmazonECS_FullAccess
  • AWSCloudFormationFullAccess
    (過剰かもしれないです)

ECRにimageをpush

Dockerfile.prodを利用してimageをbuildし、それをECRへpushします。

まずは、以下コマンドを実行しimageをbuildします。

$ docker build -t {アカウントID}.dkr.ecr.ap-southeast-1.amazonaws.com/stringsvc -f Dockerfile.prod . 

その後、以下コマンドを用いてECRのリポジトリを作成します。

$ aws ecr create-repository --repository-name stringsvc --region ap-southeast-1

これらが完了した場合、imageをpushします。

$ docker push {アカウントID}.dkr.ecr.ap-southeast-1.amazonaws.com/stringsvc

これで、上記URLからimageを利用することができます。
もし、これらのコマンドの過程でAWSやDockerへの認証へ失敗している、というようなことがある場合は、このあたりのページを参考にしてみてください。

https://qiita.com/mSakakibara/items/e5b60877c8724d5bf89d
https://docs.aws.amazon.com/ja_jp/AmazonECR/latest/userguide/getting-started-cli.html

Amazon ECS用のコンテキスト作成

先ほど作成したIAMユーザーの認証情報を用います。

$ docker context create ecs stringsvc
? Create a Docker context using: AWS secret and token credentials
Retrieve or create AWS Access Key and Secret on https://console.aws.amazon.com/iam/home?#security_credential
? AWS Access Key ID MYACCESSKEYID
? Enter AWS Secret Access Key *********
? Region ap-southeast-1
Successfully created ecs context "stringsvc"

実行後、docker context lsで作成したコンテキストがあることを確認し、

$ docker context use stringsvc

などでコンテキストを変更しましょう。

その後、docker compose upを行うだけでAWS上で自動的にデプロイされます。
これには数分から数十分かかることもあるため、気長に待ちましょう。
特に初回は20程度かかるようなこともあるかと思います。

$ docker compose -f production.yml up 
WARNING services.scale: unsupported attribute        
[+] Running 5/10
 ⠋ stringsvc              CreateInProgress User Initiated                                                                                         19.0s
 ⠿ DefaultNetwork         CreateComplete                                                                                                           5.2s
 ⠋ LoadBalancer           CreateInProgress Resource creation Initiated                                                                            16.0s
 ⠋ AppTCP8080TargetGroup  CreateInProgress Resource creation Initiated                                                                            16.0s
 ⠿ LogGroup               CreateComplete                                                                                                           1.2s
 ⠋ CloudMap               CreateInProgress Resource creation Initiated                                                                            16.0s
 ⠋ AppTaskExecutionRole   CreateInProgress Resource creation Initiated                                                                            16.0s
 ⠿ Cluster                CreateComplete                                                                                                           5.2s
 ⠿ DefaultNetworkIngress  CreateComplete                                                                                                           1.0s
 ⠿ Default8080Ingress     CreateComplete                          

起動確認後、docker compose psを行うことによって、どのようなURL,portからアクセスできるか確認できます。

$ docker compose ps
NAME                                              COMMAND             SERVICE             STATUS              PORTS
task/stringsvc/62faa404da0d4f77a03511947730d396   ""                  app                 Running             {hogehogehogehoge}.elb.us-east-1.amazonaws.com:8080:8080->8080/tcp

また、AWS コンソールなどでどのようなサービスを利用しているかを確認することができます。

https://www.wakuwakubank.com/posts/644-aws-fargate-ecs-basic/#index_id4

ハマったポイント

ここからは、ハマったポイントについて触れていければと思います。

buildせずにそのままデプロイしようとした

docker-composeのままデプロイできるということで、buildとかもそのままできるのかな?と思っていましたができず、少し後になって、自作のimageを使うような場合はECRなどにpushする必要があることに気づきました。このような、通常のdocker,docker-composeを扱う際との違いを明確に意識していなかったために起きた問題です。

volumeを使用しようとしていた

上記に加え、当初のproduction.ymlではvolumesを使ってgo run main.goを行おうとしており、これが原因でAWS CloudFormationのスタック作成に失敗していました。
volumeはファイルシステムにバインドするものなので、もし仮にvolumeを使いたい場合はAWS EFSなどを用いて、仮想的にマウントできるファイルストレージを使う必要があり、ローカルで行ういわゆる

~~~~~~
   volumes:
     - .:/app
~~~~~~

というようなことはできません。
とはいえ、今回はそもそも本番環境ではgoアプリケーションそのものをbuildしてしまえばvolumeを使う必要もなかったので、妙に複雑化することなく、原因さえ分かってしまえば解決しました。

最後に

今回はアプリケーションサーバー1台のみという質素なcompose.ymlでしたが、とはいえ想像以上に簡単にデプロイすることができました。
今後はフロントエンドやネットワーク構成なども含めて、手元で作ったアプリケーションを手軽に公開していきたいですね。

参考にさせていただいた記事

https://medium.com/@m_kikuchi/go-kitのサンプル読んでみた-cd043a8f0ae5
https://qiita.com/morita-toyscreation/items/e30cd35133f0b3f81452#dockerfile
https://qiita.com/mSakakibara/items/e5b60877c8724d5bf89d
https://www.wakuwakubank.com/posts/644-aws-fargate-ecs-basic/#index_id4

Discussion