この記事は続きものになっています。今回は実践編です。
前回→紹介編
前回のあらすじ
クラウド開発環境はいいぞ。
構築してみる
ここからは実際にクラウド開発環境を構築していきましょう!
なお今回はMacからやってますんで、Windowsだとコマンドとかちょっと違う場合があるかもしれません。
まあ細かいところが違うだけで流れは同じです。なんかできなさそうなことあったら調べてみてください。代替するものはあるはずです。
1. Compute Engineのインスタンスを作成する
Compute Engineにアクセスし、プロジェクトが無い場合はプロジェクトを作成します。
課金の設定がなければ課金設定に飛ぶので、カード情報とかを入力して課金情報を登録しましょう。
課金情報が無ければ当然インスタンスを使用することはできません。
課金情報も登録できたら、Compute Engine APIを有効にします。有効にするだけなら特にお金はかかりません。
有効になったらこんな画面になります!インスタンスを作りましょう!
インスタンス作成画面では、スペックを選択することができ、そのスペックに応じた費用を右側に出してくれます。
自分は以下の設定にしていますが、こちらは臨機応変に変えていきましょう。クラウドの強みであります💪
項目 | 値 |
---|---|
シリーズ | N1 |
マシンタイプ | n1-standard-2(2 vCPU、7.5 GB メモリ) |
OS | Debian |
ディスク種類 | バランス永続ディスク |
ディスク容量 | 30GB |
その他 | デフォルト |
ファイヤーウォールには何もチェックを入れないようにしましょう。後で設定します
作成ボタンを押せばインスタンスが作成され、さっきは何も無かったインスタンス一覧に新しくインスタンスが起動した状態で追加されます!
ステータスが緑のチェックになり、外部IPにそれっぽいIPアドレスが入ってると思います(ここでは隠してます)
これで無事インスタンスが作成されました!しかしこれだけだとまだインスタンスに入って作業できません。次にインスタンスにSSH接続できるようにしましょう。
2. 作成したインスタンスに接続できるようにする
外部IP右の「SSH」を使えばブラウザからインスタンスに入れはするんですが、まあ使い勝手は悪いので自分のローカル環境からSSH接続してインスタンスに入るようにします。
2の1. ssh-keygen
する
SSH接続するために、公開鍵と秘密鍵を作成しましょう。
適当にターミナル開いて
$ ssh-keygen
sshキーの保存先が聞かれます。デフォルトは~/.ssh/id_rsa
です。
複数の鍵を作る場合は名前分けたほうがいいですが、まだ何もない場合はデフォルトで良いのでそのままEnterでもOKです。
その後パスフレーズが聞かれますが、こちらは特に何も書かずにEnterでいいと思います。1
こんなやつ出てくれば成功です
The key's randomart image is:
+---[RSA 3072]----+
| . oo. o. |
| o o.=.. |
| + =.o. |
| oooE |
| S .o * . |
| .oo .% + |
| .==+B B . |
| o+O+ * . |
| .=o++ . |
+----[SHA256]-----+
ls ~/.ssh
でファイルを確認すると、id_rsa
とid_rsa.pub
が生成されているはずです。
2の2. 公開鍵をGCPに登録
Compute EngineのSSH認証鍵から公開鍵(id_rsa.pub
)を登録します
出てきた入力欄にid_rsa.pub
の中身をコピペしてください。
これで保存すればOKです!
2の3. 接続の確認
これで起動しているインスタンスにSSH接続できるようになってるはずです!
接続してみましょう
# ssh [ホスト] 的な感じ
$ ssh 111.111.111.111
ホストのところには入りたいインスタンスの外部IPを入れましょう。
鍵ファイルの名前を自分で指定した場合はファイル先のパスを指定してやる必要があります。例えばこんな感じ
$ ssh 111.11.1.0 -i ~/.ssh/bo_id_rsa
初回ログイン時はなんかcontinue connecting?
とか聞かれますが、適当にyesしておきましょう。
なんかターミナルの感じが変われば成功です!これでインスタンスに接続できるようになりました!
2の4. ファイアウォールの設定
このままだとインスタンスにhttpで接続できない(=ブラウザから実行結果が開けない)ので、ファイアウォールを設定してhttpとhttpsで接続できるようにします。
ファイアウォールの設定を開きます。
デフォルトでなんか色々ありますが、全部使わないので削除しちゃって大丈夫です。
必要になったらルール作りゃいいんすよ
色々設定する項目ありますが、以下のように設定しましょう
項目 | なんなんそれ | 設定例 |
---|---|---|
名前 | ルールの名前。そのまんま | bo-dev-ip |
ターゲット | このルールを適用するインスタンスをフィルタリングできる。設定分けないならネットワーク上のすべてのインスタンス でおk |
ネットワーク上のすべてのインスタンス |
ソースフィルタ | フィルタを設定して接続範囲を限定する。IP範囲を選択 | IP 範囲 |
ソースIPの範囲 | 指定したIPアドレスでしか接続できないようにする。 自分のIPアドレスの確認はこちらから。サブネットマスクまで指定する必要がありますが、 /32 って書いときゃ大丈夫です |
114.51.4.19/32 |
プロトコルとポート | 接続できるポート番号を指定する。プロトコルはTCPで、SSH、http、httpsで接続できるようにしたいのでそれぞれに対応する番号22,80,443 を入力します。 |
✅ tcp: 22,80,443 |
その他 | デフォルトでおk |
あとは「作成」ボタンを押して完了です👍
今一度SSH接続をやってみて接続できることを確認しておきましょう。22番ポートが解放されていればSSH接続できますので、それでファイアウォール設定がうまくいってるか確認できます。
3. エディタからインスタンスに接続する
ここではVS Codeでの接続例を提示します。他のエディタの接続方法はわからんぽよなので、他のエディタを使用する場合、このステップはなんとかご自身で頑張ってください。
3の1. 拡張機能のインストール
ぼくが大好きRemote - SSHくんをインストールしましょう
VS Codeの拡張機能で「Remote SSH」なんかで検索すれば一番上に出てきます。それをインストールしましょう。
3の2. 設定ファイルを書く
以下のいずれかの方法で設定ファイル(~/.ssh/config
)を開きます
-
F1
→remote
と検索して出てくるRemote-SSH: Open SSH Configuration File...
を選択 - Remote - SSHで追加されるタブ「リモートエクスプローラー」の設定アイコンをクリックし、
Remote-SSH: Open SSH Configuration File...
を選択 - nanoとかviで直接開く(
nano ~/.ssh/config
)
設定ファイルが開けたら、以下の設定を追記します。
Host bo-dev # 名前。なんでもいい
# 起動させたインスタンスの外部IP。
HostName 11.45.14.19
# 公開鍵についてるユーザー名。
# 今回のようにssh-keygenでユーザー名指定してないならローカルでログイン中のいつものユーザー名でおk
User bo-yakitarako
# 秘密鍵への絶対パス。ssh-keygenでファイル指定してないなら「~/.ssh/id_rsa」になるはず
IdentityFile /Users/bo-yakitarako/.ssh/bo_id_rsa
言わなくても大丈夫だと思うけど上記のものは一例であって、そのまんま書いてもダメですからね?各々で対応するものに値を設定してください。
これで上記の場合はbo-dev
という接続先に接続する準備が整いました。
3の3. 接続!
以下のいずれかの方法で接続します。
設定がうまくいってれば、VS CodeでSSHに接続した形になります!
うまく接続できたら最初にエクスプローラーからフォルダを開いておきましょう。フォルダを開いておけば、後から直接開いたフォルダに行けるようになります。
Connect to Host...
から来るよりフォルダに行ったほうがなにかと便利やね
こうして | こうじゃ |
---|---|
ひとまずOKしてユーザーのホームディレクトリを開いておきます。
フォルダから入るには以下の方法があります。
3の4. watch上限を最大にする
なにやらwatch上限なるものがあって、HMRとかgitとかが監視するファイルの最大数が設定されているらしいのです。
デフォルトでも65536
くらいあるっぽいのででかくなんなきゃ大丈夫だと思うんですが、これ超えちゃうとHMRができなくなっちゃうんで、一応最大まで上げておきましょう。
このコマンドを実行してくだせえ
$ sudo sh -c 'echo fs.inotify.max_user_watches=524288 >> /etc/sysctl.conf' && sudo sysctl -p
fs.inotify.max_user_watches=524288
とか言われたら適用できてます🌞
3の5. 拡張機能入れる
ローカルとクラウドで拡張機能の管理は別なので、ローカルに入ってる拡張機能は入れ直す必要があります。
といってもLocal - インストール済み
って具合にローカルで入れてる拡張機能に絞って表示してくれて楽にインストールできると思います。ありがたや...ありがたや...
Remote-SSHのトラブルあるある
Q. Permission Denied
とか言われて接続できない!
以下の原因が考えられます。
Q. Could not establish connection
とか言われるんだけど?
→**known_hosts
にIPが登録されてるかも**
同時に起動しないと複数のインスタンスで同じ外部IPを共有します。known_hosts
には最初にcontinueしたインスタンスとそのときのIPアドレスが登録されるのですが、それ以外のインスタンスでそのIPアドレスに接続しようとするとこのエラーになります。
対応策は簡単で、~/.ssh/known_hosts
を開いて該当するIPアドレスが書かれてる行を削除するだけです。
4. nginxでhttp接続できるようにする
ブラウザからアクセスできるようにするために、nginxを設定します。
ここからはDockerでやったほうが良さみですが、Dockerよくわかんない(大敗)のでシステム直接いじっていきます。
とにもかくにもまずはインスールじゃい!
$ sudo apt-get update
$ sudo apt-get install nginx
インストールが完了したっぽかったら、nginxが動いてるか確認しましょう。
$ sudo systemctl status nginx
なにやら仰々しく色々でてきてたらOKです。
そうしたら、設定ファイルを書きます。
詳しい説明は省きますが、/etc/nginx/conf.d
以下に設定ファイル(***.conf
)を置くようにしていきます。
$ nano /etc/nginx/conf.d/dev.conf
nano
とかvi
で開いたら、以下のように入力します。(nano
とかvi
の使い方はググってちょ)
server {
listen 80;
server_name bo-dev;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Server $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
location / {
proxy_pass http://localhost:3000/;
}
}
書けたら保存して、nginxを再起動させて設定を適用しましょう。
$ sudo systemctl restart nginx
特になんも言われなければおkでごぜーます。
ブラウザからhttp://bo-dev
に接続すると、nginxがプロキシになってインスタンス内のlocalhost:3000
に繋いでくれるという流れですね。
とはいえbo-dev
の名前解決もやってないですし、そもそもlocalhost:3000
も立ってないのでこの段階では接続はできません。
5. 開発用ドメインを名前解決する
突然http://bo-dev
が出てきてちょっと困惑したかもしれません。申し訳NASA
というのもクラウド環境にlocalhost
で接続するのはちょっとアレなんで、開発用ドメインを勝手に用意してそこに接続する形にしたいんですよね。
その開発用ドメインというのが今回でいうところのbo-dev
ドメインです。これはわりと自由に決められるのでお好きな文字列をお使いいただけます。
自由に決められると言いつつ、多分これを見てるあなたにbo-dev
は使えないかもしれませんが。は?
というのもですね、他の人が既にどこかで開発用ドメインを名前解決してたら使えないっぽいんですよね。bo-dev
は僕が名前解決しちゃったのでみなさんは使えないというわけです。
でももしかしたら使えるかも。DNSようわからんぽよ...
ちなみにdev
は使えませんでした。残念でした〜
話が逸れましたね。名前解決するとかなんか物々しいこと言ってますが、そんなに難しいことじゃありません。ローカルPCのhostsファイルに1行追加すればいいだけです。
ローカルPCだからね!インスタンスのほうじゃないからね!間違えないでね!
- Mac/Linuxの場合:
nano /etc/hosts
で開きます。(sudo
必要かも) - Windowsの場合:
Winキー+R
を押して出てきた入力欄にdrivers
と入力→etc
フォルダに行ってその中のhosts
を管理者権限で開く
末尾に以下のように入力して保存しまつ。
# 開発用ドメイン
xxx.xxx.xxx.xxx XXXXXX
なにやらxxx
とか並んでますが**xxx.xxx.xxx.xxx
にはインスタンスの外部IPを、XXXXXX
には開発用ドメインを入力します**。bo-dev
の場合は
# 開発用ドメイン
114.51.4.19 bo-dev
みたいな感じです。
保存できたらブラウザからhttp://開発用ドメイン
に接続してみましょう。nginxの502画面が開くはずです。
ここで、外部IPは間違えてないのにうまく接続できなかったら残念ながらそのドメインは使えません。別のドメインをhosts
ファイルに書きましょう。
そしてこれでようやく準備が整いました。長かったぜベイベー
6. フロントエンド開発するぜ!
ぶっちゃけあとはローカルで開発するときの感覚と変わりないです。Node.js入れてyarn入れて2create-xxx-app
してっていういつもの流れですね。
今回は試しにNext.jsやってみますね。
最初にNode.jsのバージョン変えたりしたいのでnvm
入れます。
↓nvmの最新バージョンのインストールスクリプトはこちらから↓
https://github.com/nvm-sh/nvm#install-script
以下のcurl
はバージョンが古い可能性があるので最新バージョンのインストールスクリプトをご使用くだせえ
$ curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash
$ source ~/.bashrc
$ nvm ls-remote # インストールできるバージョンの確認
$ nvm install v14.18.0 # 現時点の良さげなバージョン入れました
$ node --version # Node.jsが入ってることの確認
$ npm install --global yarn # グッバイnpmお前のことは忘れねえぜ
yarn
入れるとこまでです。特別なことは特にやってないですね。
それではここでは~/projects
以下にNext.jsプロジェクトを展開したいと思います。この辺はお好みですね
$ mkdir ~/projects
$ cd ~/projects
$ yarn create next-app demo --typescript
いにしゃらいず終わったらフォルダをプロジェクトのトップのところで開き直しましょう。ここでは~/projects/demo
ですね。
これで | こうして | こうじゃ! |
---|---|---|
フォルダが開けたらいつも通りターミナルも開いておきましょう。これで開発プロジェクトを開くのも容易になったZOY!
したらyarn dev
して開発サーバーを立ち上げましょう。
compiled successfully
になったらさっき502になってたhttp://開発用ドメイン
にアクセスし直してみましょう。
成し遂げたぜ。
盛り上がってきたのでちょっとタイトル変えてみましょう。
<h1 className={styles.title}>
- Welcome to <a href="https://nextjs.org">Next.js!</a>
+ Welcome to <a href="https://nextjs.org">成し遂げたぜ。</a>
</h1>
ふおおおおおおおおおお変更がすぐ反映されてりゅうううううううううううううううううう
このように、**クラウド環境でもHMRでの開発が可能です!**スゴイデスネ
あとは煮るなり焼くなり好きに開発していきましょう。
注意点
インスタンスは再起動するたびに外部IPが変わります。なので、起動する度に~/.ssh/config
と/etc/hosts
を書き換える必要があります。
毎回ファイル開いて変えるのもめんどいんで、僕はコマンドラインから$ devip xxx.xxx.xxx.xxx
ってすると、~/.ssh/config
と/etc/hosts
の中身が入力したIPアドレスに変わるようにしてます。
具体的にはTypeScriptでスクリプト書いて.zshrc
でエイリアス設定してる感じです。
スクリプトはこんな感じ↓
import { readFileSync, writeFileSync } from 'fs';
(() => {
if (process.argv.length <= 4) {
console.log('引数ねンだわ');
return;
}
const [, , hostTitle, domain, IP] = process.argv;
const etcReg = new RegExp(`^[0-9|\\.]+[\\s]+${domain}$`);
const hostsLines = readFileSync('/etc/hosts', 'utf-8')
.split('\n')
.map((text) => {
if (etcReg.test(text)) {
return `${IP} ${domain}`;
}
return text;
});
writeFileSync('/etc/hosts', hostsLines.join('\n'));
type ConfigLines = [string[], boolean];
const configFilePath = '/Users/bo-yakitarako/.ssh/config';
const [configLines] = readFileSync(configFilePath, 'utf-8')
.split('\n')
.reduce(
([lines, canRewrite], text) => {
if (canRewrite && text.includes('HostName')) {
const spaces = [...Array(text.indexOf('HostName') + 1)].join(' ');
return [[...lines, `${spaces}HostName ${IP}`], false] as ConfigLines;
}
const reg = new RegExp(`^[\\s]*Host ${hostTitle}$`);
const isUpdate = canRewrite || reg.test(text);
return [[...lines, text], isUpdate] as ConfigLines;
},
[[], false] as ConfigLines
);
writeFileSync(configFilePath, configLines.join('\n'));
console.log(`${IP}に書き換えといたわよ`);
})();
$ ts-node ./src/index.ts hostTitle domain IP
みたいに使います。(実際にはコンパイルしてます)
-
hostTitle
:~/.ssh/config
で作った設定の名前 -
domain
: 開発用ドメイン -
IP
: インスタンスの外部IPアドレス
hostTitle
とdomain
を指定してIPアドレスだけコマンドライン引数にするという形でエイリアスを作ってます。
alias devip='(){node ~/Desktop/Node/ipreset/build/index.js bo-dev bo-dev $1}'
おわりに
思ったより長くなってしまいましたが、これにてクラウド開発環境の構築は完了です。
ただまだできていないことがあります。httpsでの接続です。
これまたかなり曲者だったので、気が向いたらまた別で記事にしようと思います。
ほいじゃさいなら〜