月 5.5ドルで使える Vultr で nginx-proxy を構築して frourio を Docker で動かす!
はじめに
この記事は、いままで Docker を開発環境としてお気持ちで使っていた初心者が書いています。
玄人の方々におかれましては、暖かい目で見守って頂けますと幸いです。
(誤っている情報などありましたらディスカッションにてお願いします…!)
最初は下の記事で紹介されている Vercel + Heroku での運用を考えていたのですが、Free Dyno があまりよくなかったので(スリープしたり、時間枠の概念だったり)悩んでいました。
👇 Vercel + Heroku 構成の紹介
そこで知人が Docker ベースでの VPS 運用を勧めてくれて、その知人の手厚いサポートの末になんとか構築できました。本当にありがとうございます!
(単純比較できるものではないですが、Heroku Hobby は $7/月、Vultr は $5.5/月 なので自分で運用したほうが安い!)
完成図
GitHub Actions で rsync 転送後、VPS にてイメージ作成とコンテナ作成・起動をしています。
イメージを GitHub Actions で作ってから VPS にデプロイするべきなのですが、それはもう少し理解を深めてからということで……(いつか続編を書くかも)
フロントエンドは Vercel でホストしています。フロントエンドのデプロイも少しコツが要るのですが、それについても Vercel + Heroku 記事をお読みいただけると…!
最近話題の「frourio」を無料でサクッとデプロイする方法(Vercel + Heroku) #フロントエンドのデプロイ
VPS を借りる
Vultr について
今回は Vultr で $5/mo の SSD Cloud Instance を借りてみます。
この記事をお読みの方のほとんどは消費税 10% の国にお住まいだと思いますので、$5 に 10% の消費税が加算されてタイトルの $5.5 となるわけです。
Vultr は海外運営の VPS ですが、なんと Tokyo リージョンがあります。
私は知人におすすめされて知ったのですが、Tokyo リージョンがあることと UI の綺麗さで気に入りました(こら)
トップページでメールアドレスとパスワードを入れて、名前とか住所とかを入れて、メールの認証をして決済情報まで入れておきましょう。
ちなみに管理画面はこんな感じ。
Deploy New Instance
新規インスタンスを作ります。
High Frequency だと 2.4 倍くらいのお値段で NVMe SSD になる…?そこまで性能が要るわけではないので Cloud Compute を選びます。
Location はもちろん Tokyo で、Type は好みでいいと思います。
Size はタイトルに従って $5/mo。一番下に Additional 10% Consumption Tax applicable to your account
とあるように、アカウントの設定によって消費税が加算されます。
項目 | 内容 |
---|---|
Choose Server | Cloud Compute |
Server Location | Tokyo |
Server Type | Ubuntu 20.04 |
Server Size | 25 GB SSD ; $5/mo |
Additional Features | ここはお好みで |
Startup Script | あるなら登録するとよさそう |
SSH Keys | root に適用されます |
Server Hostname & Label | 付けなくても作れます |
スクリーンショット(長い)
セットアップ
VPS をセットアップするのが久々すぎて、ほぼこの記事のとおりにやってました。
この場を借りて感謝 🙏
ここでは SSH Port は変更せず、MySQL 用に 3306 を開けておきます。
バックアップ
Snapshots
手動で保存する Snapshot は現在無料のようです。保存個数・期間も無制限なのかな…?
Stored snapshots are currently free - pricing subject to change.
👇 Snapshots の画面はこんな感じ
Automatic Backups
定期的に保存してくれる Backup は、サーバー代金の 20% が追加徴収されます。
注意すべき点として、Backup として保存されるのは最新の 2 つまでのようです。
ただ、Backup を Snapshot に変換すると、先述した通り無期限?保存されます。
実行頻度は 毎日, 1 日おき, 毎週, 毎月 の中から選べます。
私は週に 1 回、UTC 日曜日 18 時 = JST 月曜日 午前 3 時 に設定しています。
👇 Backups の画面はこんな感じ(あいにくまだ一度も取られていません…)
これを設定しても $6.6/月 なのでお財布に優しい!
私はいつ環境を壊すかわからないので自動バックアップを頼ることにしました><
nginx-proxy を構築する
ディレクトリ構成はこんな感じ。
/
└ var/
└ docker/
├ proxy/
│ └ docker-compose.yml
└ app/
├ docker-compose.yml
├ kostl-back/
│ ├ docker-compose.yml
│ └ Dockerfile
└ kostl-next/
├ docker-compose.yml
└ Dockerfile
docker, docker-compose をいれる
Vultr のドキュメントに従っていれます。
- Install Docker CE on Ubuntu 18.04 - 20.04 - Vultr.com
- Install Docker Compose on Ubuntu 20.04 - Vultr.com
ユーザーがドキュメントに寄稿できる(報奨制度有り)ので、大量の記事があります。
ここもうれしいポイント。
自分を docker グループに入れる
$ sudo usermod -aG docker subaru
$ id subaru
# uid=1000(subaru) gid=1000(subaru) groups=1000(subaru),27(sudo),998(docker)
ディレクトリを用意
sudo mkdir /var/docker
sudo chown -R subaru:docker /var/docker
chmod 775 -R /var/docker
cd /var/docker
mkdir app && mkdir proxy
network の作成
あとで使うことになる front_bridge
, back_bridge
を先に作成しておきます。
$ docker network create front_bridge
$ docker network create back_bridge
一覧を見たり、詳細を見たり……
$ docker network ls
$ docker network inspect front_bridge
docker-compose.yml を書く
nginx-proxy, Let's Encrypt
version: "3"
services:
nginx-proxy:
image: jwilder/nginx-proxy
restart: on-failure
labels:
- com.github.jrcs.letsencrypt_nginx_proxy_companion.nginx_proxy=jwilder/nginx-proxy
container_name: nginx-proxy
privileged: true
ports:
- "80:80"
- "443:443"
volumes:
- proxy:/etc/nginx/vhost.d
- proxy:/usr/share/nginx/html
- /var/run/docker.sock:/tmp/docker.sock:ro
- ./certs:/etc/nginx/certs:ro
networks:
- front_bridge
letsencrypt:
image: jrcs/letsencrypt-nginx-proxy-companion
restart: on-failure
container_name: letsencrypt-nginx
depends_on:
- nginx-proxy
volumes:
- proxy:/etc/nginx/vhost.d
- proxy:/usr/share/nginx/html
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./certs:/etc/nginx/certs:rw
networks:
- front_bridge
networks:
front_bridge:
external: true
volumes:
proxy:
↓ほぼこの記事そのままです。この場を借りて感謝 🙏
MySQL
version: "3"
services:
mysql:
image: mysql:5.7
restart: on-failure
container_name: docker-mysql
ports:
- "3306:3306"
volumes:
- ./mysql-5.7-data:/var/lib/mysql
environment:
MYSQL_ROOT_PASSWORD: your_root_password
networks:
- back_bridge
networks:
back_bridge:
external: true
データベースは全アプリ共通で 1 つの MySQL を用意して、3306 を開放しています。
本当はポート変えるべきかもしれない けど私は覚えられないので変えてません
nginx-proxy, MySQL を起動
$ docker-compose up -d
$ docker-compose up -d
初回起動ですし、ログも追っておきましょう。
$ docker-compose logs -f
アプリを準備する
まずはほぼ共通の docker-compose.yml
から。
nginx-proxy と Let's Encrypt の設定は各アプリの環境変数で行います。
version: "3.8"
services:
hoge.example.com:
build: .
restart: on-failure
container_name: hoge.example.com
environment:
VIRTUAL_HOST: hoge.example.com
LETSENCRYPT_HOST: hoge.example.com
LETSENCRYPT_EMAIL: mail@exmaple.com
networks:
- front_bridge
- back_bridge
networks:
front_bridge:
external: true
back_bridge:
external: true
サービス名・コンテナ名は他とかぶらないものであればお好みでよさそう。
2021.01.12 追記
当初ディレクトリ名をhoge-dir
としていましたが、分かりづらいためkostl-next
に置き換えました
frourio
Dockerfile
公式ドキュメント を参考にしながらプロジェクトを作成し、こんな感じの Dockerfile
を用意します。
FROM node:15
RUN mkdir /src
RUN mkdir /src/server
WORKDIR /src
COPY /server/package.json /server/yarn.lock ./server/
RUN yarn install --cwd ./server
COPY . .
EXPOSE 8080
CMD yarn build:server && yarn start:server
yarn install
は server 側だけで問題ありません(ルートディレクトリでの install は不要)
↓ほぼこの記事そのままです。この場を借りて感謝 🙏
環境変数
server/.env
を作成します。
SERVER_IP=0.0.0.0
BASE_PATH=/api
DATABASE_URL=mysql://kostl:your_password@mysql:3306/kostl-next
API_ORIGIN=https://api.next.kostl.info
JWT_SECRET=your_jwt_secret
USER_ID=id
USER_PASS=password
DATABASE_URL
のホストは、サービス名(今回は mysql
)で名前解決されます。
Lumen
👇 本題から逸れるので折りたたみ & Dockerfile のみ
Dockerfile
FROM php:7.4-apache
WORKDIR /var/www/html
ENV APACHE_DOCUMENT_ROOT=/var/www/html/public
# install
RUN apt-get update \
&& apt-get install -y libonig-dev zlib1g-dev libfreetype6-dev libjpeg62-turbo-dev libpng-dev git zip unzip
RUN docker-php-ext-install pdo_mysql
# gd
RUN docker-php-ext-configure gd --with-freetype --with-jpeg \
&& docker-php-ext-install -j$(nproc) gd
# configure docroot
RUN sed -ri -e 's!/var/www/html!${APACHE_DOCUMENT_ROOT}!g' /etc/apache2/sites-available/*.conf \
&& sed -ri -e 's!/var/www/!${APACHE_DOCUMENT_ROOT}!g' /etc/apache2/apache2.conf /etc/apache2/conf-available/*.conf
COPY ./php.ini /usr/local/etc/php
# prepare composer
COPY /usr/bin/composer /usr/bin/composer
ENV COMPOSER_ALLOW_SUPERUSER 1
# composer install
COPY composer.json /tmp/composer.json
COPY composer.lock /tmp/composer.lock
RUN composer install --no-scripts --no-autoloader -d /tmp
# prepare lumen
COPY . .
RUN mv -n /tmp/vendor ./ \
&& composer dump-autoload
RUN php artisan migrate && php artisan db:seed --force
# enable module
RUN a2enmod rewrite
アプリを起動
$ docker-compose up -d
初回起動ですし、ログも追っておきましょう。
$ docker-compose logs -f
ドメインに A・AAAA レコードを設定する
ドメイン関連でやることは 1 つ。A・AAAA レコードを設定するだけです。
VPS の IP アドレスを設定すればドメイン設定は完了!
IPv4 (A レコード) は Overview にあるのですが、IPv6 (AAAA レコード) は Settings > IPv6 にあります。
これは現時点では IPv6 がオプション扱いだからだと思われます。(#Deploy New Instance の Additional Features で選択式です)
2020.01.10 追記
IPv6 (AAAA レコード) を追記しました
GitHub Actions でデプロイを自動化
デプロイ用のユーザーを作る
まずはサーバー側で deploy
ユーザーを作り、docker
グループをつけて Docker の操作権限を与えます。
$ sudo useradd -m deploy
$ sudo passwd deploy
$ sudo usermod -aG docker deploy
$ id deploy
そしてローカルで deploy
の SSH 鍵を用意しておきます(あとで GitHub の Secrets に登録する)
$ mkdir ~/.ssh/vultr-deploy
$ ssh-keygen -t rsa -b 4096 -C "your_key_comment" -f ~/.ssh/vultr-deploy/id_rsa
$ ssh-copy-id -i ~/.ssh/vultr-deploy/id_rsa.pub deploy@198.51.100.0 # example
workflow を書く
lint & type check → deploy with rsync → Docker build & up
の workflow がこんな感じです。
lint & type check には create-frourio-app で CI に GitHub Actions を選択した場合に生成されるテストを使用しています。
rsync の exclude も frourio に合わせて server/.env
を指定しています。
👇 めちゃくちゃ長いので折りたたみ
.github/workflows/deploy.yml
name: deploy
on:
push:
branches:
- master
jobs:
test:
name: lint and type check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: setup Node.js
uses: actions/setup-node@v1
with:
node-version: 14
- uses: actions/cache@v2
id: client-yarn-cache
with:
path: "node_modules"
key: client-yarn-${{ hashFiles('yarn.lock') }}
- uses: actions/cache@v2
id: server-yarn-cache
with:
path: "server/node_modules"
key: server-yarn-${{ hashFiles('server/yarn.lock') }}
- run: yarn install
if: steps.client-yarn-cache.outputs.cache-hit != 'true'
- run: yarn install --cwd server
if: steps.server-yarn-cache.outputs.cache-hit != 'true'
- run: yarn lint
- run: |
sudo systemctl start mysql.service
echo "DATABASE_URL=mysql://root:root@localhost:3306/test" > server/prisma/.env
- run: yarn typecheck
deploy:
name: deploy with rsync
runs-on: ubuntu-latest
needs: test
steps:
- uses: actions/checkout@v2
- name: prepare .ssh dir
run: mkdir -p .ssh && chmod 700 .ssh
- name: prepare ssh key
run: echo "$SSH_KEY" > .ssh/id_rsa && chmod 600 .ssh/id_rsa
env:
SSH_KEY: ${{ secrets.SSH_KEY }}
- name: set permission
run: chmod -R 775 * && sudo groupadd -f docker && sudo useradd deploy -g docker && sudo chown -R deploy:docker *
- name: push with rsync
run: |
rsync -rlptgoD -O --delete --exclude ".git/" --exclude "server/.env" \
-e "ssh -i .ssh/id_rsa -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -p ${SSH_PORT}" \
* $SSH_USER@$SSH_HOST:$DIR
env:
DIR: ${{ secrets.DEPLOY_DIR }}
SSH_HOST: ${{ secrets.SSH_HOST }}
SSH_USER: ${{ secrets.SSH_USER }}
SSH_PORT: ${{ secrets.SSH_PORT }}
docker:
name: build and up
runs-on: ubuntu-latest
needs: deploy
steps:
- name: build & up -d
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.SSH_HOST }}
username: ${{ secrets.SSH_USER }}
key: ${{ secrets.SSH_KEY }}
port: ${{ secrets.SSH_PORT }}
envs: DIR
script_stop: true
script: |
cd $DIR
docker-compose build
docker-compose up -d
env:
DIR: ${{ secrets.DEPLOY_DIR }}
Secrets を登録する
GitHub リポジトリの Settings > Secrets に Secrets を登録します。
ここで登録した情報は workflow 内で secrets.SSH_PORT
のように参照できます。
DEPLOY_DIR
(/var/docker/app/kostl-next
),
SSH_HOST
( IP Address ),
SSH_PORT
(設定したやつ),
SSH_USER
(deploy
),
SSH_KEY
(さっき作った秘密鍵)
を入れておきましょう。
動かしてみる
workflow を commit して push すると実際に走ります。
ちゃんと順番に実行されることが確認できれば OK!
build, up も問題なく行われていることが確認できます 🎉
おわりに
最後までお読みいただきありがとうございました!
この記事が少しでもお役にたてれば幸いです😊
良き nginx-proxy & frourio ライフを~!
参考
大変参考になりました!ありがとうございます!
VPS
- 【チュートリアル】VPSを借りたらやるべき最低限のセキュリティ初期設定 | Enjoy IT Life
- お前らのSSH Keysの作り方は間違っている - Qiita
- ssh-copy-idで公開鍵を渡す - Qiita
Docker
- Docker 基礎
- ネットワーク
- nginx-proxy
frourio
- 最近話題の「frourio」を無料でサクッとデプロイする方法(Vercel + Heroku)
- Fast and type-safe full stack framework, for TypeScript | frourio
GitHub Actions
-
ConoHa WING に GitHub Actions でデプロイしよう!
(ダイレクトマーケティング)
Discussion
質問です。
冒頭の構成図がとても綺麗だと思ったのですが、こちらはどんなツールを使って作られたのでしょうか?
ありがとうございます。
申し訳ないのですが、これはツールによる制作物ではなく、Illustrator で自作したものになります…!
なるほど!流石にこんな綺麗な図がシュッと作れるサービスはないですよね笑
素晴らしいです!