このサイトの構成について
いつの日か撮った置物の犬
🐤 はじめに
こんにちは。yanoseaです。
このサイトをデプロイしてから見えてきた、「あれもしたい、これもしたい」を色々やっていました。
現時点で自分が納得するところまで手直しできたので、このタイミングでこのサイトの構成について書いてみたいと思います。
筆者が記事執筆初心者のため、こちらの記事を参考に書いていきます。
この記事はなに?
- アウトプットを頑張っていく!という目標にむけて手始めにこのサイトの技術構成を解説兼備忘録として書き残しておいたものです
- 個人サイトを開設したい方は参考になるかもしれません
この記事の想定読者は?
- 筆者 (備忘録なので)
- 個人サイトを開設してみたい方
この記事のねらいは?
- 筆者のアウトプット実践
- 筆者の備忘録
- 各技術についての情報を少しでも解説する
⚠️ ご注意
- 内容に筆者の個人的な解釈を多分に含んでいることにご注意ください
- 間違った内容を書いている可能性があるためお気付きの場合はコメントやTwitter等でお気兼ねなくご指摘いただけますと幸いです
🏁 結論
構成は下図のとおりです。
🏗️ インフラ
このサイトはXserver VPSのLinuxマシンにデプロイされています。
昨今だとNetlifyやVercelにデプロイするのがパフォーマンス面やコスト面で優れていると思っています。
では、何故VPS上にデプロイしているのか?それは…。
- どこからでもSSHでいじれるLinuxマシンが欲しかった (建前)
- 先にVPSやドメインを契約してしまった (本音)
自分のサイトを作りたいと思っていたけれどなかなか動けなかったので、自分を追い込むために先んじてインフラに投資したからです。
結果的にどこでもLinuxマシンに接続して色々試せる環境を手に入れたので、これはこれでいいかと自分に腑に落とさせています。
ただ、やはりパフォーマンスとコストは大事なので1年の契約が切れる頃には乗り換えられるように準備しようかなと早々に考えています。
参考程度にXserverに支払った金額を書いておきます。キャンペーンがちょっとありがたいですね。
VPS料金 : ¥8,311
ドメイン料金 : ¥946
SSL証明書発行料金 : ¥1,045
合計 : ¥10,302
Xserverを選択した技術的な理由は特にありません。
契約した当時のTwitterのTLが「Xserverはいいぞ」と盛り上がっていたので飛びついただけです。
🖥️ サーバー構成
OSはArch Linuxを採用しています。Archを選択した理由はメインの私用PCのWindowsのWSLで使っているためです。
そして、このサイトはそのVPSのLinux上で稼働する2台のDockerコンテナで運用しています。
ひとつはWebサーバーが稼働しているコンテナで、もうひとつはAPIサーバーが稼働しているコンテナです。
このVPS自体はXserverの設定からポート80と443をWebサーバー用に開放しています。
また、GitHub Actionsおよび筆者が接続するためにエフェメラルポートを一つを開放してSSH接続に使用しています。
SSH接続するためにsshdの設定をしていますが、ここではこれ以上触れないでおきます。
🐋 Docker
サーバー運用にあたって、コンテナを用いて稼働させることにしました。
Dockerを選択した理由はVPSを必要以上に汚したくなかったのと、VPSを引っ越すことになっても再利用できると考えたからです。
恥ずかしながら業務で使用したことがなかったので、使ってみたかったというのもあります。
docker-compose
を使用してDockerコンテナの起動や終了をコントロールしています。
複数のコンテナの操作・管理を簡単にしてくれるツールです。Dockerfile
と呼ばれるコンテナの設定ファイルをWebサーバーの分とAPIサーバーの分で2つ用意し、docker-compose
用の設定ファイルdocker-compose.yml
からそれらを参照します。
インフラをコード化しておく、いわゆるInfrastracture as Code (IaC)
というやつですね。
一般に以下のメリットがあると言われています。
- なるべく手作業を減らし、ヒューマンエラーを防止する
- 保守性の向上
個人的には設定ファイルを見れば使用しているコンテナが一目でわかるところにメリットを感じています。
docker-compose.yml
は以下のとおりです。
version: "3.8"
services:
back:
container_name: $BACK_CONTAINER_NAME
build:
context: ./back
dockerfile: Dockerfile
args:
- BACK_PORT=$BACK_PORT
ports:
- $BACK_PORT:$BACK_PORT
env_file: .env
front:
container_name: $FRONT_CONTAINER_NAME
build:
context: ./front
dockerfile: Dockerfile
args:
- FRONT_PORT=$FRONT_PORT
ports:
- $FRONT_PORT:$FRONT_PORT
env_file: .env
volumes:
- ./$FRONT_SSL_PATH:/etc/nginx/ssl:ro
2つのコンテナ設定がservices
配下に書かれているのがお分かりいただけるかと思います。back
と命名されているものがAPIサーバーのコンテナで、front
と命名されているものがWebサーバーのコンテナです。
$BACK_PORT
などの環境変数を使用していますが、これは.env
ファイルで設定しているものです。.env
という名前のファイルがdocker-compose.yml
と同階層に配置してあれば、docker-compose
実行時に読み込んでdocker-compose.yml
の中で展開してくれます。
このおかげでdocker-compose
を使用するshellに環境変数を設定しておく必要がなくなります。
また、Webサーバー側のコンテナに$FRONT_SSL_PATH
という環境変数を使用しています。中身はVPSのとあるパスです。
このパスに向けてGitHub Actionsとsecrets変数を用いてSSL証明書と鍵ファイルを書き込み、
Webサーバー側のコンテナにマウントしてhttps接続に対応しています。
🌐 Webサーバー (front)
WebサーバーはNginxを採用しました。
Nginxを採用した理由ですが、まずシェアの観点からNginxとApacheの二択に絞っていました。
最終的には業務での運用経験があまりないNginxを選択するに至りました。
公開先のディレクトリにAstroでビルドした静的サイトを配置しています。
このコンテナの設定にあたるDockerfileは以下のとおりです。
FROM node:21.6-slim as builder
WORKDIR /app
COPY package.json ./
COPY pnpm-lock.yaml ./
RUN npm install -g pnpm && pnpm install
COPY . .
RUN pnpm build
FROM nginx:alpine AS runtime
ARG FRONT_PORT
COPY nginx.conf.template /etc/nginx/templates/nginx.conf.template
COPY --from=builder /app/dist /usr/share/nginx/html
EXPOSE $FRONT_PORT
ポイントは2点あります。
マルチステージビルドの採用
Nginxのコンテナ起動時にAstroで静的サイトのビルド
とNginxの立ち上げとビルドした静的サイトのデプロイ
の
2ステップを踏むようにしています。
これにより立ち上がったコンテナ内にソースコードやnode_modulesなどの不要なファイル群が残ってしまうことを防ぐことができ、
コンテナの軽量化とクリーンな環境でのNginx稼動が実現しています。Nginx設定ファイルの適用
COPY nginx.conf.template /etc/nginx/templates/nginx.conf.template
で
nginxの設定のテンプレートファイルをコンテナ内へコピーしています。
これにより立ち上がったコンテナで稼働するNginxのリバースプロキシやSSLなどの設定を事前にファイルで保持しておくことができます。
📡 APIサーバー(back)
Golangでビルドしたバイナリを実行してAPIサーバーを立てています。
.envファイルにエフェメラルポート番号を定義して、docker-compose.yml
経由でDockerfile
へ渡してListenさせています。
クライアントからAPIのエンドポイントへのアクセスをNginxで一度受け止めて、
リバースプロキシでAPIサーバーへのリクエストをルーティングしています。
このコンテナの設定にあたるDockerfileは以下のとおりです。
FROM golang:1.22 as builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . ./
RUN CGO_ENABLED=0 GOOS=linux go build -o /main .
FROM alpine:latest
ARG BACK_PORT
RUN apk --no-cache add ca-certificates
WORKDIR /app
COPY --from=builder /main ./
EXPOSE $BACK_PORT
CMD ["./main"]
こちらもマルチステージビルドを採用しています。
APIサーバーではSpotifyのWeb APIを実行して筆者の再生中、または最後に再生したSpotify上の楽曲の情報を取得して
クライアントに返却しています。
🧑🚀 フロントエンド実装
フロントエンドはAstroというWebフレームワークを使用しました。
Astroについてはこちらの記事がとても分かりやすく簡潔に書かれていたため、この紹介のみとさせていただきます。
CSSフレームワークにはtailwindcssを使用しています。
筆者は昨今話題によく上がるモダンなフロントエンド技術を今までの業務で使用したことがありません。
(.NET MVC + jQuery とかSpring Boot + jQuery みたいな構成をずっとやっていました。業務システム開発あるある?)
主観ですがフロントエンド周りの技術は複雑で難しいイメージがあり、
シンプルかつ管理が楽なものが良いと考えたためこれらの採用に至りました。
今後はReactやVue.jsなどを使ったものを作って遊んでみたいです。
🐀 バックエンド実装
バックエンドはGolangを採用しました。 Web API フレームワークとしてEchoを採用しました。
Golangを選択した理由はTwitterでつながりのある方たちがよく使ってらっしゃり、
筆者自身も業務で経験のない比較的モダンな言語を使ってみたかったからです。
Echoは単純に「Go API フレームワーク」なんて検索をかけて、一番注目度が高いように見えたからです。
結果的にシンプルに書けるものだったのでかなり気に入っています。
🚀 CD
デプロイはGitHub Actionsで自動化しています。デプロイはmainブランチにpushされた時に実行されます。
リポジトリの設定でmainブランチに直接pushするのは制限しているため、PRをマージした時のみ実行されます。
workflowの設定ファイルは以下のとおりです。
name: deploy
on:
push:
branches:
- main
jobs:
deploy:
name: deploy
runs-on: ubuntu-latest
steps:
- name: deploy
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.SSH_HOST_IP }}
username: ${{ secrets.SSH_USER_NAME }}
key: ${{ secrets.SSH_PRIVATE_KEY }}
port: ${{ secrets.SSH_PORT }}
script: |
sudo pacman -Syyu --noconfirm
cd ${{ secrets.REPOSITORY_PATH }}
sh ${{ secrets.DOCKER_STOP_SCRIPT }}
cd
rm -fr ${{ secrets.REPOSITORY_PATH }}
git clone ${{ secrets.REPOSITORY_URL }} ${{ secrets.REPOSITORY_PATH }}
cd ${{ secrets.REPOSITORY_PATH }}
echo "${{ secrets.ENV_FILE }}" > .env
mkdir -p ${{ secrets.SSL_PATH }}
echo "${{ secrets.SSL_CRT }}" > ${{ secrets.SSL_PATH }}/${{ secrets.SSL_CRT_FILE_NAME }}
echo "${{ secrets.SSL_PRIVATE_KEY }}" > ${{ secrets.SSL_PATH }}/${{ secrets.SSL_PRIVATE_KEY_FILE_NAME }}
sh ${{ secrets.DOCKER_START_SCRIPT }}
ワークフローは以下のステップを踏んでいます。
- secrets変数を使用してVPSへSSH接続
- 各コンテナの終了用スクリプトの実行
- ローカルリポジトリの削除
- ポートフォリオサイト用リポジトリのクローン
- secrets変数を使用して本番環境用.envファイルを作成
- secrets変数を使用してWEBサーバーのコンテナにマウントするSSL証明書関連ファイルを作成
- 各コンテナの開始用スクリプトの実行
🐔 おわりに
ここまで読んでいただきありがとうございます。(ほんと心から…。)
拙い文章でしたが、ある程度ねらいを達成できるような内容を書けたかなと思っています。
以降はもっとライトな記事を雑に投稿していこうと思っています。よろしければまた記事を読んでいただければ幸いです!
ではまた!
2024-05-07
#tech #astro #golang #docker #xserver