はじめに
本記事は 個人開発 Advent Calendar 2019 25日目の記事です。
最近connpassに掲載されている勉強会を地図を見ながら検索できるようなサイトを作りました。
(もともと同僚が勉強会でこんな感じのアプリを作っておりそれに触発された)
使った技術としては
フロント: typescript、react、redux、circleci、cloudfront、s3、terraform
バックエンド: go、gin、docker、nginx、circleci、ecs、terraform
な感じです。
仕事ではあまりインフラまわりを触ることがなく、CI/CD環境の知見があまりないが、それっぽいものを自分で作ってみようとしました。
フロント
アプリケーション
アプリケーションの土台はcreate-react-appを使いtypescriptで書きました。
stateの管理にはredux、ミドルウェアにredux sagaを使いました。
また、reduxの型定義にtypescript-fsa、reducerでのオブジェクトのマージにimmerを使っています。
SSRをせずに、動的なOGPに対応するためにprerender-spa-pluginを使ったため、customize-cra、react-app-rewiredを使ってCRAのデフォルトのwebpack設定を上書きしたりもしました。prerender-spa-pluginのことは、別記事にも書いています
また、apiのfetch中に出てくるアニメーションはlottieにあったものを使いました。
環境構築
cloudfront、s3の環境をterraformで作成しました。
別記事に詳しく書いています。
CI/CDの流れ
- circleci
- pushされるたびにビルド
- masterへのコミットならビルドしたファイルをs3にあげる
バックエンド
アプリケーション
golangを使いました。フレームワークにgin、cuiにcobraを使っています。
apiでもcuiでも共通のロジックを使うようにしています。クリーンアーキテクチャを意識はしましたができてるかはよくわからないです。
docker
マルチステージビルドを使って、ローカルで開発する時に利用するイメージと、ECRにあげる本番用イメージを別にしています。
# 開発用
FROM golang:alpine as builder
RUN apk update \
&& apk add --no-cache git \
&& go get github.com/oxequa/realize
WORKDIR /app
COPY go.mod .
COPY go.sum .
RUN go mod download
COPY . .
RUN GOOS=linux GOARCH=amd64 go build -o /main
# 本番用
FROM alpine:3.9
COPY --from=builder /main .
ENTRYPOINT ["/main"]
EXPOSE 7777
開発用のdocker-composeです。
realizeを使ってホットリロードができるようにしています。
version: "3.5"
services:
app:
build:
context: .
target: builder
volumes:
- ./:/app
command: realize start --server
environment:
- API_VERSION=development
ports:
- 7777:7777
nginx:
build: nginx
ports:
- 80:80
depends_on:
- app
本番用のdocker-composeです。ECRにあげたイメージを使っています。
また、現在のリリースバージョンの確認ができるようにコミットのSHA-1を環境変数(API_VERSION)として渡しています。ALBのヘルスチェック用に用意しているAPIを叩くと、このSHA-1が返ってくるようにしてます。
このdocker-composeはecs-cliに引数として渡すものになるため、ecs-cliが対応しているversionである必要があります。(3.5とかだと無理でした)
version: "3"
services:
app:
image: "882275384674.dkr.ecr.ap-northeast-1.amazonaws.com/connpass-map-api-app:${SHA1}"
environment:
- API_VERSION="${SHA1}"
ports:
- 7777:7777
nginx:
image: "882275384674.dkr.ecr.ap-northeast-1.amazonaws.com/connpass-map-api-nginx:${SHA1}"
ports:
- 80:80
depends_on:
- app
環境構築
vpc、サブネットなどのNW環境とALBやターゲットグループ、ECSのクラスターなどをterraformで作成しました。
別記事に詳しく書いています。
CI/CD
-
circleci
- featureやmasterブランチにpushがされる
- そのコミットのSHA-1をタグにしてアプリのイメージをビルド
- ECRにイメージをpush
-
デプロイするスクリプト(ローカルで実行)
- どのブランチでリリースをしたいか選択
- ecs-cliを使ってecsのサービス、タスクをリリース
近道
上記の環境を作るに当たってインフラまわりが苦手な人がひっかかりそうな所としては
- ecs
- terraform
- circleci
- デプロイするシェルスクリプト
な気がしてます。これらは僕自身も今も苦手ですが、
ecsならリリースにecs-cliを使えば、docker-compose.ymlをそのまま流用する形でecsのタスクが作れる。(dockerは勉強する必要あるがecsの独自のタスク定義の書き方とかは勉強しなくてよくなる)
terraformならいい本があるのでベーシックな環境ならこの本の写経でなんとかなる。
circleciなら便利な処理をパッケージにしてくれているorbsを使えば結構楽できる。
シェルスクリプトは勉強すればいい。(これは近道がない気がしている)
という感じでどれも今なら便利なツールや本が揃っているので個人開発でそれっぽい環境を作るハードルはかなり低くなってると思います。