Next.js のプロジェクトを VPS 上の Docker にデプロイする【その5】
Next.js のプロジェクトを VPS 上の Docker にデプロイする【その1】、【その2】、【その3】、【その4】の続きです。
前回、遂に、自動で Next.js のプロジェクトを VPS 上の Docker にデプロイすることができました。
今回は開発・運用がしやすいワークフローを目指します。実際に独自ドメインの設定も行う予定です。
開発・運用のフローを考える
前回は、main ブランチに push されると GitHub Container Registry にビルドし、VPS にデプロイするワークフローを作成しました。
実運用するにあたり、図のようにステージング環境を用意していこうと思います。
ブランチ
ブランチは以下のように設定することにします。
main
: 本番環境staging
: ステージング環境develop
: 開発環境
役割
ステージング環境は、本番環境とポートとドメインのみを変更したものにします。
開発環境は、ローカル環境ですぐに変更が確認できる状態のものにします。
今回は以下のドメインでアクセスできるようにします。
main
: donuts.cookin.dev に配置staging
: donuts-stagnig.cookin.dev に配置develop
: http://localhost:3000(ローカルPC上)
Dockerfile ファイル
各環境で、Dockerfile
を以下の名前で用意します。
main
: prod.Dockerfilestaging
: stg.Dockerfiledevelop
: dev.Dockerfile
Docker Compose の利用
Docker Compose を利用するのは develop 環境のみになります。
main
: なしstaging
: なしdevelop
: docker-compose.dev.yml
GitHub Actions のワークフローの作成
GitHub Actions のワークフローは本番環境とステージング環境でそれぞれ作成します。
main
: deploy.prod.ymlstaging
: deploy.stg.ymldevelop
: なし
各ブランチの作成
上記に合わせてブランチの作成を行います。
# 作業ディレクトリに移動
$ cd ~/NextProjects/donuts-site
# staging ブランチの作成とリモートへの反映
$ git branch staging
$ git push origin staging
# develop ブランチの作成とリモートへの反映
$ git branch develop
$ git push origin develop
# develop にチェックアウトしておく
$ git checkout develop
各ファイルの用意
上記を元にファイルを作成します。
deploy.stg.yml
、deploy.prod.yml
を作成して、以下のようなフォルダ構成になりました。
.
├── .eslintrc.json
├── .git
├── .github
│ └── workflows
│ ├── deploy.prod.yml
│ └── deploy.stg.yml
├── .gitignore
├── .next
├── README.md
├── dev.Dockerfile
├── docker-compose.dev.yml
├── next-env.d.ts
├── next.config.js
├── package.json
├── pages
├── prod.Dockerfile
├── public
├── styles
├── tsconfig.json
└── yarn.lock
ステージング環境のDockerfile
ステージング環境用のstg.Dockerfile
の中身を書きます。
ポート番号を 49152-65535番ポート(ダイナミック/プライベートポート番号)から適当に決めて設定します。
##### deps ステージ #####
FROM node:16-alpine AS deps
RUN apk add --no-cache libc6-compat
WORKDIR /app
COPY package.json yarn.lock* package-lock.json* pnpm-lock.yaml* ./
RUN \
if [ -f yarn.lock ]; then yarn install --frozen-lockfile; \
elif [ -f package-lock.json ]; then npm ci; \
elif [ -f pnpm-lock.yaml ]; then yarn global add pnpm && pnpm i; \
else echo "Lockfile not found." && exit 1; \
fi
##### builder ステージ #####
FROM node:16-alpine AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN yarn build
##### runner ステージ #####
FROM node:16-alpine AS runner
WORKDIR /app
ENV NODE_ENV=production
RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs
COPY --from=builder /app/public ./public
COPY --from=builder /app/package.json ./package.json
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
USER nextjs
EXPOSE 49200
ENV PORT 49200
CMD ["node", "server.js"]
ステージング環境のワークフロー
次にステージング環境用のワークフローを.github/workflows/deploy.stg.yml
に書きます。
先ほど指定したポート番号とDockerfileを指定し、ステージング用にイメージを作成するようにします。
実行タイミングは、staging
ブランチにプッシュされた場合にします。
name: Deploy to Sakura VPS Staging
# staging ブランチにプッシュされた時に実行する
on:
push:
branches: [staging]
# 手動実行時のログを設定
workflow_dispatch:
inputs:
logLevel:
description: 'Log level'
required: true
default: 'warning'
jobs:
deploy:
runs-on: ubuntu-latest
container: node:16
steps:
# チェックアウト
- uses: actions/checkout@v3
# Github Container Registry へビルドしてイメージを格納
- name: Build and Publish to Github Container Registry
uses: elgohr/Publish-Docker-Github-Action@master
with:
# 本番とステージングでイメージ名を変更
name: GitHubのユーザ名(lowercase)/donutssite/donuts-site-image-staging
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
dockerfile: stg.Dockerfile
tags: latest
# VPSへのデプロイ
- name: Deploy to Sakura VPS
uses: appleboy/ssh-action@master
env:
GITHUB_USERNAME: ${{ github.actor }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
host: ${{ secrets.DEPLOY_HOST }}
port: ${{ secrets.DEPLOY_PORT }}
username: ${{ secrets.DEPLOY_USER }}
key: ${{ secrets.DEPLOY_KEY }}
envs: GITHUB_USERNAME, GITHUB_TOKEN
script: |
docker login ghcr.io -u $GITHUB_USERNAME -p $GITHUB_TOKEN
docker image pull ghcr.io/GitHubのユーザ名(lowercase)/donutssite/donuts-site-image-staging:latest
docker container stop donuts-site
docker container rm donuts-site
docker system prune -f
docker container run --name donuts-site -dit -p 49200:49200 --restart=always ghcr.io/GitHubのユーザ名(lowercase)/donutssite/donuts-site-image-staging:latest
GitHub にプッシュする
develop
ブランチから上記の変更をプッシュしておきます。
# 作業ディレクトリに移動する
$ cd ~/NextProjects/donuts-site
$ git add .
$ git commit -m ":rocket: Add staging environment"
$ git push origin develop
develop ブランチに変更があってもアクションが実行されないことを確認しておきます。
develop
ブランチをstaging
ブランチにマージします。
staging ブランチのワークフローが動き出します。
デプロイが完了したので http://IPアドレス:49200 へアクセスしてみます。(ポート番号は先ほど指定したもの)
無事に表示されました😊
続いて、staging ブランチを main にマージします。
main ブランチのポートも適当に変更しました。http://IPアドレス:本番環境のポート へアクセスして表示されればOKです。
これでステージング環境の構築ができました。
独自ドメインの設定
以下を前提として設定してきます。
- VPS(Ubuntu)上に nginx の設定がされている
- ドメインが取得されている
今回はこのドメインのサブドメインを設定して
donuts.cookin.dev
を本番環境とします。
# sites-available ディレクトリにドメイン名のファイルを作成する
% sudo vi /etc/nginx/sites-available/donuts.cookin.dev
server {
listen 80;
server_name donuts.cookin.dev;
location / {
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-Proto http;
proxy_pass http://localhost:本番環境のポート;
}
}
# Nginxが起動時に読み取るsites-enabledディレクトリにリンクを作成して、ファイルを有効にする
% sudo ln -s /etc/nginx/sites-available/donuts.cookin.dev /etc/nginx/sites-enabled/
# nginx.conf の構文が正しいかをチェックする
% sudo nginx -t
# サーバを再起動する
% sudo systemctl restart nginx
ドメインが反映されるまで時間がかかるのでしばらく待ちます。
http://donuts.cookin.dev/ にアクセスして無事に反映されました。
最後にCertbotを使って証明書を発行し、SSL化しておきます。
# Certbot と Nginx プラグインをインストール
% sudo apt install certbot python3-certbot-nginx
# Nginx プラグインで Certbot を実行
% sudo certbot --nginx -d donuts.cookin.dev
# リダイレクトの設定をする (2)
Please choose whether or not to redirect HTTP traffic to HTTPS, removing HTTP access.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1: No redirect - Make no further changes to the webserver configuration.
2: Redirect - Make all requests redirect to secure HTTPS access. Choose this for
new sites, or if you're confident your site works on HTTPS. You can undo this
change by editing your web server's configuration.
Select the appropriate number [1-2] then [enter] (press 'c' to cancel): 2
# 証明書の自動更新の確認
% sudo systemctl status certbot.timer
# 証明書の更新テスト
% sudo certbot renew --dry-run
これによりsites-available
に配置したサーバブロックの設定が変更されます。
server {
server_name donuts.cookin.dev;
location / {
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-Proto https;
proxy_pass http://localhost:本番のポート番号;
}
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/donuts.cookin.dev/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/donuts.cookin.dev/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}
server {
if ($host = donuts.cookin.dev) {
return 301 https://$host$request_uri;
} # managed by Certbot
listen 80;
server_name donuts.cookin.dev;
return 404; # managed by Certbot
}
ステージング環境のドメイン設定
ステージング環境も同様に設定していきます。donuts-staging.cookin.dev
としました。
# sites-available ディレクトリにドメイン名のファイルを作成する
% sudo vi /etc/nginx/sites-available/donuts-staging.cookin.dev
server {
listen 80;
server_name donuts.cookin.dev;
location / {
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-Proto http;
proxy_pass http://localhost:49200;
}
}
# Nginxが起動時に読み取るsites-enabledディレクトリにリンクを作成して、ファイルを有効にする
% sudo ln -s /etc/nginx/sites-available/donuts-staging.cookin.dev /etc/nginx/sites-enabled/
# nginx.conf の構文が正しいかをチェックする
% sudo nginx -t
# サーバを再起動する
% sudo systemctl restart nginx
# Nginx プラグインで Certbot を実行
% sudo certbot --nginx -d donuts-staging.cookin.dev
# リダイレクトの設定をする (2)
Please choose whether or not to redirect HTTP traffic to HTTPS, removing HTTP access.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1: No redirect - Make no further changes to the webserver configuration.
2: Redirect - Make all requests redirect to secure HTTPS access. Choose this for
new sites, or if you're confident your site works on HTTPS. You can undo this
change by editing your web server's configuration.
Select the appropriate number [1-2] then [enter] (press 'c' to cancel): 2
これで https://donuts-staging.cookin.dev で確認できるようになりました。
おわりに
今回で、Next.js + Docker + VPS での開発・運用環境の構築奮闘記は終わりになります。
参考記事などでは1記事でまとまっているようなことを、10記事以上かけてじっくり取り組んできました。
何度も手戻りが発生していて参考にはなりづらいと思うので、まとめ版記事も用意する予定です。