この記事は、Yahoo! JAPAN 18 新卒 2 Advent Calendar 2018の4日目の記事です。
Yahoo! JAPAN の新卒1年目が有志で行っているアドベントカレンダーです。
次回は@orleika さんによる「アセンブリでQuine」です。
注意
この記事では決してCaaS
を否定している訳ではありません。
商用や開発環境ということに関しては言えば、とても適していると思います。
ただ今回の条件ではIaaS
(VPSサーバ
)が適しているというだけです。
前提
個人 が 学習用途 込みで複数のサイトを公開することを想定しています。
連続稼働を必要としていますが、大きな責任は伴わない状況です。
責任が伴う場合は、サーバの管理を他に任せることのできる環境(CaaS
やPaaS
など)を選択してください。
目的
- 複数のパソコンで開発が行える環境が欲しい
- サーバの機能を後々追加するかもしれない
- 自分がこれまでしてきたアウトプットをまとめたサイトが欲しい
- 今後公開するサイトが増える可能性がある
- サイトを公開するため連続稼働を望む
これらの目的を達成するため、次の構成で作成します。
作成するもの
- Git Server
- リバースプロキシサーバ(nginx)
- Node.jsアプリ(サイト公開の準備のみ)
準備するもの
- VPSサーバ(以下で言及)
- ドメイン(本記事ではサンプルとして
walk8243.com
を使用)
サーバをIaaS、それもVPSにした理由を考えてみましょう。
サーバの比較
IaaSとCaaSの比較
IaaS
- メリット
- ディスク容量が許す限り機能の追加は可能
- 機能の設定が自由
- デメリット
- 機能の追加を自分でする必要がある(マネジメントシステムにより補助が可能)
- 追加した機能の管理をしなければならない
CaaS
- メリット
- 多数のコンテナイメージが用意されている
- コンテナイメージにより機能の設定が簡単
- 機能の管理はコンテナイメージの更新で可能
- デメリット
- 機能追加がコンテナに引っ張られる
VPSとクラウドの比較
VPS
- メリット
- 値段が安い
- サーバにグローバルIPアドレスが付いてくる
- 料金は前払い
- デメリット
- サーバのディスク容量やメモリサイズを変更するときは契約のし直し
クラウド
- メリット
- ディスク容量やメモリサイズを簡単に変更できる
- サービスが多種多様
- オートスケーラを付ければ自動でサイズ変更してくれる
- 料金は使った分だけで後払い
- デメリット
- 値段は割高
- サーバとグローバルIPアドレスは別サービス
VPSを選んだ理由
- グローバルIPアドレスが必須
- サーバがダウンしてもすぐに復旧すれば大丈夫
- 機能を自分で追加・設定したい(学習のため)
- なるべく安く済ませたい
では実際に手を動かして、環境を作っていきましょう。
サーバセットアップ
借りたサーバは次のものです。
https://www.onamae.com/server/vps/
- サーバ管理会社
お名前.com - メモリ
1GB - CPU
2コア - HDD
100GB
OSセットアップ
デフォルトでインストールされているものが CentOS6.5
です。
それをそのまま使いました。
Gitサーバ
この後作成するNode.jsアプリはセキュリティを考えると、ソースコードの公開はするべきではありません。
複数のパソコンで開発が行える環境を整えるために、Gitサーバを作成しましょう。
詳しくは、以前書いたこの記事をご覧ください。
使用するユーザは root
(スーパーユーザ) と git
(gitサーバ用) です。
# gitをインストール
[root@Server:~]# yum install git
# リポジトリを作成
[git@Server:~]# mkdir sample.git
[git@Server:~]# git init sample.git --bare --shared
# リポジトリをクローン
[Client:~]# git clone git@{ServerIP}:sample.git
ざっと流すとこんな感じです。
詳しくは、以前書いたこの記事をご覧ください(再び)。
リバースプロキシサーバ
今回、一つのサーバ内に複数のサイトを公開する予定です。
そのサイトはNode.jsを使って作成するつもりです。
そのため、それぞれのNode.jsアプリへリクエストを振り分けるためにリバースプロキシサーバを作成することとしました。
使用実績、ドキュメント量、設定ファイルで構成できる、リクエストの処理方法というところを総合的に考えて apache
と nginx
の2択としました。
駆動方法の違いから、使用するものは nginx
にしました。
両者の比較はApacheとNginxについて比較を参考にしてください。
以下はデフォルト設定でのインストール方法です。
# nginx最新版(2018/11/19現在)のダウンロード
cd /usr/local/src
wget https://nginx.org/download/nginx-1.15.6.tar.gz
tar -xf nginx-1.15.6.tar.gz
cd nginx-1.15.6
# nginxのインストール
./configure
ln -s /usr/local/bin/nginx /usr/local/nginx/sbin/nginx
which nginx
# nginxのService登録
vi /etc/init.d/nginx # サンプルコードに内容記載
chmod +x /etc/init.d/nginx
chkconfig --add nginx
chkconfig --list | grep nginx
chkconfig nginx on
service nginx start
ps aux | grep nginx
これから作成する複数のWebアプリを振り分けられるようになりました。
設定ファイルを編集して、自由にリクエストの振り分けを行ってみてください。
サンプルコード
Tips
キャッシュ
キャッシュは通過する全ての箇所で設定されている有効期限のうち、最短のものが適用されます。
キャッシュが動作しない場合、それぞれのサーバ間でのリクエスト・レスポンスのヘッダーも確認してください。
リダイレクト
return
を使うことでリダイレクトさせることができます。
そのとき、HTTPステータスコードとURLを指定できます。
リダイレクトさせずにリクエストを投げる場合は、proxy_pass
を使用してください。
Node.jsアプリ
Nodeのインストールは nvm
を用いました。
https://github.com/creationix/nvm
# nvmのインストール
cd /usr/local/src
wget -qO- https://raw.githubusercontent.com/creationix/nvm/v0.33.11/install.sh | bash
nvm --version
# nodeのインストールと確認
nvm install lts/dubnium
node -v
npm -v
サーバサイドのソースコードは、セキュリティリスクを伴うため不特定多数の人が見れる環境にあることはよくありません。
なので、先ほど作成したGitサーバでソースコードを管理しましょう。
サイトを公開するための環境を作ることが目的なので、この章は軽く流します。
個人サイト
GitHubやQiitaをまとめたサイトとして作りました。
そのため、このサイトではGitHubやQiitaのAPIを使っています。
また、先ほど作成したリバースプロキシを用いて、テスト環境も作成しています。
GitHub API v3
https://developer.github.com/v3/
[サンプルコード](#GitHub API - Node.js)
API使用に必要なトークンは、ココから取得してください。
Qiita API v2
https://qiita.com/api/v2/docs
[サンプルコード](#Qiita API - Node.js)
外部サイト
現状所属しているコミュニティのサイトを運営できないかなと思い、そのための環境を作っていました。
Expressを使って、テンプレートエンジンはtwigを指定しました。
現状はnginxで作成したリバースプロキシが正常に稼働しているかの確認のために使用しています。
Express のアプリケーション生成プログラム
# 初期設定
git init
npm init --yes
# Expressアプリの生成
npm i express
npm install express-generator -g
express -v ejs -f
# git commit
git add .
git commit -m "app init"
まとめ
したかったことは、
・自分がこれまでしてきたアウトプットをまとめたサイトが欲しい
・今後どこかのコミュニティのサイトを運営できればいいなぁ
・ある程度安定し継続して遊べる外部とつながっている環境が欲しい
ということです。
複数のサイト(Webアプリ)を持ち、継続的な環境ということで、今回はVPSサーバを選びました。
1つ借りるだけで、色々な機能を持たせられるというのは、とても懐に優しいですね。
最初にも述べた通り、上のような条件であっても、ビジネスとして捉える場合、様々な責任が伴ってくると思います。
何かあってからでは遅いです。
保障に入ると思って、Azureなり、AWSなり、Google Cloud Platformなりを使いましょう。
適材適所ということで、これからも色々使ってみて、使いどころや自分に合う合わないを見極めていきたいと思います。
サンプルコード
nginx/conf/nginx.conf
worker_processes 1;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
keepalive_timeout 65;
proxy_redirect off;
proxy_connect_timeout 3s;
proxy_cache_path /usr/local/nginx/cache keys_zone=mycache:10m max_size=128m inactive=24h;
proxy_temp_path /usr/local/nginx/cache_tmp;
proxy_cache_valid 200 302 10m;
server_name_in_redirect on;
ssl_certificate /usr/local/nginx/conf/cert.pem;
ssl_certificate_key /usr/local/nginx/conf/key.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_session_cache builtin:1000 shared:SSL:10m;
add_header X-Nginx-Cache $upstream_cache_status;
proxy_buffering on;
# walk8243.com(本番環境)
server {
listen 80;
listen 443 ssl;
server_name walk8243.com;
return 301 https://www.walk8243.com;
}
server {
listen 80;
server_name www.walk8243.com;
return 301 https://www.walk8243.com;
}
server {
listen 443 ssl;
server_name www.walk8243.com;
proxy_cache mycache;
location / {
proxy_pass http://localhost:8080;
}
}
# dev.walk8243.com(開発環境)
server {
listen 80;
server_name dev.walk8243.com;
location / {
proxy_pass http://localhost:3000;
}
}
}
/etc/init.d/nginx
#!/bin/sh
# chkconfig: 2345 99 01
# description: nginx
. /etc/init.d/functions
case "$1" in
start)
/usr/local/bin/nginx
;;
stop)
/usr/local/bin/nginx -s quit
;;
status)
;;
restart)
/usr/local/bin/nginx -s stop
/usr/local/bin/nginx
;;
reload)
/usr/local/bin/nginx -s reload
;;
*)
;;
esac
GitHub API - Node.js
const express = require('express');
const request = require('request');
const router = express.Router();
const githubToken = 'xxxxxxxxxx';
router
.get('/', (req, res, next) => {
const options = {
url: 'https://api.github.com',
headers: {
Authorization: `token ${githubToken}`,
'User-Agent': 'request'
},
};
request(options, (error, response, body) => {
if(error) return reject(error);
res.send(response.statusCode, JSON.parse(body));
});
});
Qiita API - Node.js
const express = require('express');
const request = require('request');
const router = express.Router();
const paging = 1;
const perPage = 5;
const username = 'walk8243';
router
.get('/', (req, res, next) => {
const options = {
url: `https://qiita.com/api/v2/items?page=${paging}&per_page=${perPage}&query=user:${username}`,
};
request(options, (error, response, body) => {
if(error) return reject(error);
res.send(response.statusCode, JSON.parse(body));
});
});