今回、IaCを基にAWSとCI/CD(GitHub Actions)の構築を行いました。
構築の中で躓いた点など記事にしてみました。
自己紹介
バックエンドがメインで、たまにフロントエンドを触ってるSEです。
開発経験は今年で4年前後。クラウドの開発経験はないです。
基本的な開発に加えて脆弱性やパフォーマンス・チューニングなどにも携わらせてもらっています。
クラウド開発に興味を持ってCLF~SAP辺りまでの資格を取得したので、今回実装してみました。
参考物
今回実装するに辺り、参考になった書籍などを先に記載していきます。
AWSクラウド設計完全ガイド
クラウドの設計について何もわからなかったのですが、
上記である程度イメージすることができました。
AWSではじめるクラウドセキュリティ: クラウドで学ぶセキュリティ設計/実装
CloudWatchやSNSなど、具体的な利用について不明でしたが、
上記で理解度を上げることができました。
実践Terraform AWSにおけるシステム設計とベストプラクティス
Terraformの実装について、ドキュメントを読んでもベストプラクティスがわからなかったので参考になりました。
ただ、バージョンは古いので最新バージョンはドキュメントを参照する必要があります。
GitHub CI/CD実践ガイド――持続可能なソフトウェア開発を支えるGitHub Actionsの設計と運用
CI/CDについて具体的にそもそも理解できていないなか、上記書籍を基にCI/CDの概念や実装イメージについて理解度を上げることができました。
GitHub ActionsでCI/CD構築する際に必要となるライブラリの実装方法についてまとめられています。
Terraformで実装する方法についてまとめられています。
今回作成したもの
Terraformを使用してAWS上にインフラを構築し、GitHub Actionsを用いてJava (Spring Boot) アプリケーションのCI/CDパイプラインを自動化するプロジェクトです。
機能を増やしすぎると自分が混乱してしまうので、最小構成を意識してみました。
ALBを追加してEC2をPrivateに移動しようかなとか思ったのですが、
ひとまず完成させたかったので今回は未実装になります。
CI/CD
GitHub Actionsを利用して、mainブランチへのプッシュをトリガーにCI/CDパイプラインを自動実行しました。
CI/CDの役割については、下記を実装しました。
- CI
- 単体テストの自動実施(Gradle Test)
- 静的解析(SonarQube)の更新
- .jarファイルのアップロード
- CD
- AWS認証(OIDC)
- Dockerビルド・プッシュ
- EC2デプロイ
- ECR実行
CIについては静的解析、CDはほとんど全て手こずったので
備忘録として詳細を記載していきます。
静的解析(SonarQube)
静的解析とは
単体テストは動的に実際に動かし確認しますが、静的解析はソースコードを動かさずに問題がないか確認をしてくれます。
動的と比較して静的解析の導入メリットとしては下記
- 脆弱性の検知
- 可動性・保守性の向上
- ソースコード全体の品質管理
デメリットとしては、メリットを享受するための作業コストが高いように感じました。
ローカルでソースコードを保存したタイミングにその場で解析をしてくればありがたいですが、
コミットなどをしてからでないと実施されないのは結構負担です。
ただ、完璧なソースコードではなくとも最低限修正が必要なことにフォーカスすれば
大変有効になるなと感じました。
手順は下記公式サイトから進めていき、
Administration -> Analysis Methodに進めば以降の実装方法が丁寧に記載されていました。
AWS認証(OIDC)
AWS側の操作を行うための一時認証機能。
永続的にログインして実施する方法もありますが、セキュリティの観点から
OIDCを使用したほうが万が一漏洩しても安心。
使用アクション
role-to-assumeはIAMロールからAmazonEC2ContainerRegistryReadOnlyのARN情報を
GitHubのSecrestsから登録します。
Dockerビルド・プッシュ
EC2へのデプロイのため、Docker情報をECRへプッシュしています。
- ログイン情報(REGISTRY)はECRログインのアプトプット情報を取得して使用しています。
- リポジトリはプッシュ情報を固定値として設定しています。
- イメージタグはプッシュ情報が一意となるようにgithub.sha情報を設定しています。
ECRログイン
EC2デプロイ
SSH情報を使用していEC2へログインしていきます。
本来はSSMの使用が望ましと見た気がするのですが、ひとまずSSHで進めました。
使用アクション
- ホスト名はTerraformで実装したEC2情報をoutputしてGitHubのSecretsへ登録して使用しています。
- パスワードはEC2のコンソールからキーペアで作成してSecretsへ登録しています。
EC2へログイン後、ECRへ格納された情報(my-java-app)をDocker runしてます。
ポート番号はTerraformのセキュリティグループで設定した値を反映します。
Database情報については、アプリ側のプロパティファイルで定義した値を反映します。
spring.application.name=app
# src/main/resources/application.properties
server.port=8080
# =============================================
# DATABASE CONFIGURATION
# =============================================
spring.datasource.url=${SPRING_DATASOURCE_URL:jdbc:mysql://localhost:3306/testdb}
spring.datasource.username=${SPRING_DATASOURCE_USERNAME:root}
spring.datasource.password=${SPRING_DATASOURCE_PASSWORD:password}
# 使用するデータベースのJDBCドライバ (MySQL)
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
# JPA/Hibernateの設定 (アプリケーション起動時にスキーマを検証または更新)
spring.jpa.hibernate.ddl-auto=update
Terraform(AWS)
次はTerraformで実装したAWSリソースについてまとめてみたいと思います。
IaCに共通することかなと思うのですが、依存関係を調べるのが大変でした。
理解を深めるために、各種リソースの依存関係について図表でまとめて行きたいと思います。
EC2
サーバー本体。Javaアプリ資材を配置して実行してもらってます
ECR
Javaアプリの資材をコンテナ保存してもらってます
IAM
EC2へ各リソースの権限証明書を発行しています
RDS
EC2からくるキューの処理をしています
セキュリティグループ
指定リソースのインバウンド・アウトバウンドのトラフィック制御
SNS(Simple Notification Service)
各リソースからの通知を対象に送信します
SSM(Systems Manager)
設定ファイルの一元管理
VPC
ユーザー専用の仮想ネットワーク
その他_tfstate
IaCの競合回避など管理を行います。
※今回はS3+DynamoDBで構築していますが、バージョンが上がってからS3単体で管理できるみたいです。
