背景・目的
転職やフリーランス活動を進める中で、「技術を客観的に証明できるアウトプット」の必要性を感じ、ポートフォリオを兼ねた個人ブログを開発することにしました。
また、個人的に文章を書くのが好きで、Qiitaやnote以外にも「自分の思考や構造を整理する場所」が欲しかったという動機もあります。
noteが流行していますが、あくまで外部サービスではなく、自分のドメインで完結する環境を作ることを目指します。
さらに、今後はインフラ・クラウド案件(特にGCPやAWS)に入っていきたいので、ブログの構成自体もインフラ視点で設計・運用していきます。
以前から「ポートフォリオを作らなきゃ」と思いつつも、正直面倒でした。
しかし、最近は CursorなどAIエージェントの登場で環境構築の効率が上がり、「今なら作れる」と思い立ちました。
環境
- コンテナ
- Node.js: 20
- AlmaLinux: 9
- Apache httpd: 2.4系
- アプリ
- Next.js: 14.2.33
- React: 18.2.0
- ビルド/デプロイ
- Cloud Build
- Skaffold: v2.16.1
- Cloud Deploy
- Cloud Run
- Artifact Registry
AWSではなくGCPを選んだ理由
現在AWSアカウントが一時的に利用できない状況のため、GCPを検証も兼ねて採用しています。
GCPの利点としては、以下のような点を感じています。
- プロジェクト単位で環境を完全に分離できる(開発/本番の切り替えが楽)
- Cloud Build → Cloud Deploy → Cloud Run の流れが明確で、学習コストが低い
- 無料枠の範囲でもかなり実用的
GCPの無料トライアルについて
GCPでは、新規ユーザーに対して300ドル分(約45,000円相当)のクレジットが提供されます。
期間は12ヶ月。
Cloud RunやArtifact Registryを中心に利用すれば、無料枠でも十分に構築・検証が可能です。
コンテナ実行環境:Cloud Run
Cloud Runは「完全マネージドなコンテナ実行基盤」であり、インフラ管理を意識せずにアプリをデプロイできます。
Next.jsをDocker化したイメージをArtifact Registryにpushし、それをCloud Runにデプロイする形を取りました。
ビルドとデプロイ
gcloud builds submit --config cloudbuild.yaml
Cloud Runの特徴:
- サーバーレス
- スケーラブル(リクエスト単位でスケール)
- HTTPS自動化
- IAM連携が容易
DNS設定
AWSでいう Route53 = GCPのCloud DNS に相当します。
また、「Cloud Domains」というサービスもありますが、
ドメイン取得のUIがわかりづらかったので、今回はお名前.comでドメインを取得しました。
※ドメイン取得時の補足
- Whois情報公開代行はONにした(プライバシー保護のため)
- DNSSECを有効化→ DNSSEC公式ドキュメント
- DNSキャッシュポイズニングやなりすまし攻撃からドメインを守る仕組み。
- GCPのCloud DNS側でも簡単にON/OFFできる。
GCPでデプロイ
アプリはCursorで雛形を作り、
Cloud Build + Cloud Deploy + Cloud Run の流れでデプロイ。
GitHub Actionsは経験済みなので、今回はGCP純正ツールで統一しました。
結果、Cloud Run単体でページ表示までは完了。
ただし、コンテナを作り直すたびにIPアドレスが変わるため、
DNSを安定させるにはロードバランサーの設定が必要と判明。
ロードバランサー設定
GCPのServerless構成では、Serverless NEG と Google Cloud Load Balancer (GCLB) を組み合わせます。
これにより固定IPでCloud Runへリクエストを転送できるようになります。
- 固定IPを予約
gcloud compute addresses create myblog-lb-ip --global --project my-profile-and-blog
gcloud compute addresses describe myblog-lb-ip --global --project my-profile-and-blog --format='value(address)'
- SSL証明書の発行
- Let's Encryptを自動発行してくれるGCPマネージド証明書を利用。
gcloud compute ssl-certificates create myblog-cert \
--domains=ratlize.com \
--global \
--project my-profile-and-blog
- Serverless NEGの作成(Cloud Runを接続)
gcloud compute network-endpoint-groups create myblog-dev-neg \
--region=asia-northeast1 \
--network-endpoint-type=serverless \
--cloud-run-service=myblog-dev \
--project my-profile-and-blog
- Backend Serviceを作成してNEGを追加
gcloud compute backend-services create myblog-backend \
--global \
--load-balancing-scheme=EXTERNAL_MANAGED \
--protocol=HTTP \
--project my-profile-and-blog
gcloud compute backend-services add-backend myblog-backend \
--global \
--network-endpoint-group=myblog-dev-neg \
--network-endpoint-group-region=asia-northeast1 \
--project my-profile-and-blog
- URLマップ作成
gcloud compute url-maps create myblog-urlmap \
--global \
--default-service=myblog-backend \
--project my-profile-and-blog
- HTTPSプロキシ(証明書を紐付け)
gcloud compute target-https-proxies create myblog-https-proxy \
--ssl-certificates=myblog-cert \
--url-map=myblog-urlmap \
--global \
--project my-profile-and-blog
- HTTPS転送ルール(固定IP割り当て)
gcloud compute forwarding-rules create myblog-https-fr \
--address=myblog-lb-ip \
--global \
--target-https-proxy=myblog-https-proxy \
--ports=443 \
--load-balancing-scheme=EXTERNAL_MANAGED \
--project my-profile-and-blog
DNS登録
- 取得したIPv4をAレコードに登録
gcloud compute addresses describe myblog-lb-ip --global --project my-profile-and-blog --format "value(address)"
- IPv6を使う場合はAAAAレコードも追加
gcloud compute addresses describe myblog-lb-ipv6 --global --project my-profile-and-blog --format "value(address)"
Cloud DNS or お名前.com側で設定して反映を確認。
以下コマンドでSSLがACTIVEなら完了
gcloud compute ssl-certificates describe myblog-cert --global --project my-profile-and-blog --format='get(managed.status)'