初めてのクラウド、初めての Azure -簡単なサーバーアプリをオンプレから移行-

# 初めに
＊以下の記事を Qiita へ移植したものです。普段使用する技術情報プラットフォームが Qiita な方もいるかもということで。
(あとは単純に反応の違いとかあるのかという興味本位で)

https://zenn.dev/minominominoru/articles/fc40d09d89d24f

## 概要
皆さん、クラウド使ってますか？実際のところ使ったことはないという方も多いんじゃないかなと思ってたりします。そして使ってみたい、学んでみたいけど最初の一歩や学び方が分からない方も多いかなと思います。

やっぱり技術は実際に触ってみた方がイメージ掴みやすいし、学びやすいと(個人的に)思います。
なので、**手元の PC でプログラムを実行した後に、クラウドに移行してみるまでの簡単なハンズオン**を用意してみました。

なお、ちょっとしたツールのダウンロードや、アカウントの作成等は必要ですが、プログラミングの経験がない方でもできる限り簡単にできるように心がけて書いてみました。(指定したコマンドを入力するだけで試せますし、そんなに打つこともないです。)

所要時間はアカウントの作成や一部のツールのインストールを除けば **1 時間もあればできるんじゃないかな**と思ってます。もちろん、**無料で試せます。**(アカウント作成でクレカは必要だったかと思いますが)

あくまでもちょっと体験してみるくらいにはなりますが、少し Web の知識の話とかも概要だけですが入れていたりするので、**クラウドにこれから触るって方の最初の一歩の助けにでもなれたら良いな**って思います。

## 対象の人
本記事は、以下の感じの方がメインのターゲットかなと思ってます。
- 「クラウドってよく聞くけど、実際のところ何が良いの？」って方
- 「クラウドや Azure 使ったことないけどちょっと試してみたい」って方
- プログラミングの経験はあまりないが体験してみたいって方
- 何でもよいからクラウドを体験してみたいって方

なので、**例えば Azure や AWS 等に慣れている方からしたらあまり学びはないかも**です。

ただ、上記の方々以外にも、node.js を使ったことがない方なんかにも、もしかしたら楽しんでいただけるのではないかなと思います。(欲を言うとちょっとでも気になったら読んでみて欲しいとは思ってます)

## 簡単な用語の説明
本当にごく一部、最小限知っててもらえたらという感じです。
厳密な定義というよりは、**やんわりとイメージを持ってもらえたら**くらいの解説にしてます。

### 一般的な web の用語
- URL
ザックリというとネットワーク上のリソースの場所です。例えば、https://www.google.com/ という URL を開くとよく見る Google の検索画面が表示されます。

- HTTP リクエスト
あるリソース(NW 上のサーバー等)に対して処理等を要求する。例えば、 Browserで URL へアクセスして Web ページを開くのはGETです。色んな種類の HTTP リクエストがありますが、ここでは GET と POST という2種類だけ出てきます。

- エンドポイント
リクエストを送る際に「そのサーバーのどの機能を使う？」って指定をするイメージです。例えば、www.hogehoge.com/pagea にアクセスしたら pageA,www.hogehoge.com/pageb にアクセスしたら pageb が出力されるみたいに、一つのサーバーに複数のエンドポイントを用意できます。

- ローカル(ホスト)
自分の PC 上でサーバーアプリを起動する際等に「ローカルで起動する」といった表現をします。

- オンプレミス
クラウドではなく、自分/自社のネットワーク環境のことだと思っていただけたらと。インターネットとかを経由しないのでクローズドなネットワークとかローカルネットワークとか言うこともあるかもです。(厳密な定義の差等はあるかもですが割愛)


### Azure の用語
- Azure
そもそもですが、クラウドサービスの一つです。

- App Service
Azure のサービスの一種で Web アプリの作成等で使用します。
https://azure.microsoft.com/ja-jp/services/app-service/

- リソース
あるサービスの自分が使用する個体です。例えば、上記の App Service を使って複数の Web サイトを作成する際には App Service のリソースを複数作成します。

- リソースグループ
上記のリソースを管理するために使用します。色んなサービスの色んなリソースを作成することになるので、うまく管理するのに使います。

- Deploy
ザックリというと自分の作成したアプリ等をクラウド上に配置することです。

## 準備
＊私は windows 10 で実行しています。

### 前提条件
- サーバーアプリ実行用の PC : スペックとかはそんなに必要ないです。
- スマホ : 同上。ブラウザ(CHrome,Safari,Edge 等) を開けさえすれば大丈夫。
- Wi-Fi 環境 : 上記の端末を同じネットワーク(Wi-Fi 環境)に繋げます。

### 準備作業
上記前提条件の上で。

- Azure アカウント
以下から Azure アカウントを作成します。クレカが必要だったかなと思います。
https://azure.microsoft.com/ja-jp/free/

- node.js
ザックリいうと JavaScript という言語でサーバーアプリを作成する際によく使用します。
Long Term Support（LTS） の方で自分の PC にあったものを入れてください。
https://nodejs.org/ja/download/

- VSCode
コードの編集等で使用します。Azure との連携がよかったり、拡張機能で様々な機能が追加できます。
https://code.visualstudio.com/Download

また、以下の拡張機能も追加してください。

- Azure 拡張機能

Azure へのデプロイなどで使用します。各サービスごとに機能が出ていたりしますが、最低でも App Service の機能を入れてもらえたら大丈夫です。
https://marketplace.visualstudio.com/items?itemName=ms-vscode.vscode-node-azure-pack

- REST Client

サーバーアプリの機能を試すのに便利な拡張機能です。個人的には普段からよく使ってます。
https://marketplace.visualstudio.com/items?itemName=humao.rest-client


# オンプレでサーバーを実行
さて、前準備が終わったらまずはオンプレでサーバーアプリを実行してみましょう。
ちなみに、早くクラウドに触りたいって方は一応サンプルコードだけ下から落として、クラウドのところまで飛んでもらうのもありです。(ただ、node.js や Cloud が初めての方は頑張って書いたのでぜひ読んで欲しいです)

以下の Github にサンプルコードを用意しました。
https://github.com/MinoMinoMinoru/simple-restify-server/tree/master

git で clone する方法もありますが、そういった方法に慣れない方は zip でダウンロードすることもできます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/248829/735c0495-5cd4-ef74-6d64-9b9179309967.png)


とりあえず、プロジェクトファイル一式がある場所で Powershell(適宜好みのコマンド ツール)を開きましょう。Windows の方は、以下の画像のようにエクスプローラーから開くこともできます。

![](https://storage.googleapis.com/zenn-user-upload/iwmpklmbhchkm1z3jb8y1kyxd1d0)![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/248829/6472c717-542f-7565-0fab-b1df854981a3.png)



![](https://storage.googleapis.com/zenn-user-upload/zbexa6j5z2zn1td440hrkbiq5273)![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/248829/d358d09d-ec31-e25f-ebce-ded5e938d00a.png)


## serverアプリの実行
以下のコマンドで必要な module を install します。(package.json にそういう感じのことを書いてます。気になる方は npm というパッケージ管理ツールについて調べてみてください。)

```
npm install
```

続けて以下のコマンドでサーバープログラムを実行します。

```
npm start
```

まずはブラウザで以下の URL にアクセスしてみましょう。

http://localhost:3978

以下のように私が雑に作ったページが出力されます。

![](https://storage.googleapis.com/zenn-user-upload/if37c6scntj7yqzklkgpyr96wgr6)![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/248829/d19d0053-4f77-ba8d-4a7a-db800e54bcbb.png)


次に、以下の URL にアクセスしてみましょう。

http://localhost:3978/test-get

![](https://storage.googleapis.com/zenn-user-upload/7sa3ikijsqo8vfgy0lvny9m503qm)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/248829/bb097752-e0d8-943b-73d7-d15e4dc6f8d8.png)

なんか違うページが表示されているかと思います。
では、ちょっとだけ実行されているコードを見てみましょう。

``` JavaScript
const restify = require('restify');
const fs = require('fs');

// Create HTTP server
const server = restify.createServer();
server.listen(process.env.port || process.env.PORT || 3978, () => {
    console.log("Please open the following URLs in Browser")
    console.log("[URL A]");
    console.log("http://localhost:3978")

    console.log("[URL B]");
    console.log("http://localhost:3978/test-get")

    console.log("[URL C]");
    console.log("http://<Your Localhost Address>:3978/test-get");
});

// Listen for incoming requests.
server.get('/', (req, res) => {
    res.writeHead(200, { 'Content-Type': 'text/html' });
    res.write("Welcome to the start test page");
    res.end();
});

server.get('/test-get', (req, res) => {
    fs.readFile("./index.html", 'UTF-8',
        function (err, data) {
            res.writeHead(200, { 'Content-Type': 'text/html' });
            res.write(data);
            res.end();
        });
});

server.post('/test-post', (req, res) => {
    res.send({ TestBody: "Test Post Response Body" });
    res.end()
});
```

server.get() という風に書いている部分が 2 箇所あるかと存じますが、server.get('/',...) と書かれているところと、server.get('/test-get',...) と書かれているところがありますね。

'/' のエンドポイント方ではプログラム内で用意した文字列を返していて、'/test-get' のエンドポイント方では index.html というファイルを readFile していることが何となくわかるかなと思います。　(細かい話は node.js の話になるので、何となくで感じていただけたらと。)

## HTML 編集
index.html の中身を少し編集してみてください。以下が標準状態(というか私が用意したまんまの状態)です。<p> </p> の間とかを自由に編集した上で、/test-get にアクセスしてみましょう。

``` HTML
<html>
    <p>Hello from index.html</p>
</html>
```

## localhost の IPアドレスで実行
Powershell で以下のコマンドを実行してください。

```
ipconfig
```

![](https://storage.googleapis.com/zenn-user-upload/x87lt5k6vvwtyz67iv9uo9ykt8b6)![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/248829/c277ca6d-0a7c-c1ec-de7a-6e6e439d37cb.png)

ここで出力される IPv4 アドレスを使用して http://<IPv4アドレス>:3978 にアクセスしましょう。
すると、最初にアクセスしたのと同じページにアクセスできます。

## ローカルで POST 実行
先ほど実行したのは HTTP の GET リクエストです。POST リクエストに関しても試してみましょう。

落としてきたファイル群の中にある test.http というファイルを VSCode で開きます。
その後、ファイルの一番上にある "Send Request" のボタンをクリックしてみましょう。
すると以下の画像のようになります。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/248829/5b8fa17e-3f75-7216-861d-63985f88ad74.png)


画面の右側は POST リクエストを送信した結果になります。
今は同じ PC でserverを立ててリクエストを送信してますが、実際には異なる serverに POST リクエストを送ることで、処理を分けたりすることができます。

ちなみに、実際には POST の際に何等かのデータを追加して送ることで、そのデータを基にサーバー側で処理をしてもらうってことが多いです。例えば、IoT システムである地点で取得した温度のデータを POST リクエストでサーバーに投げると、サーバー側でデータベースに保存する処理をする。等が考えられます。

## スマホからアクセス(GET リクエスト)
先ほどまでは同じPC から HTTP リクエストを送信していました。今度はスマホを使ってリクエストを送ってみましょう。

サーバーのアプリは起動したままで次の処理へ入りましょう。

### Wi-Fi に繋いで
まずはスマホを PC と同じ Wi-Fi に接続させた状態で、http://<IPv4アドレス>:3978 (もしくは /test-get) にアクセスしてみます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/248829/fc938fd0-9ccd-8eaf-7bbd-cdd0efb51440.png)



こんな感じで PC で試した時と同じ表示がされますね。

### Wi-Fi から外して
次に、スマホの Wi-Fi をオフにして同じページを開いてみます。
すると、以下のようになるかと思います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/248829/1c227023-f039-df76-2a4a-0ec789b2f1f7.png)

さて、ここで先ほど PC で確認したページに繋がらない事象が発生するかと思います。
なんででしょうか？


はい、これはスマホとサーバ(PC) が異なるネットワークに存在しているために発生しています。
Wifi に接続していた際には同じネットワーク内に存在していたので、ローカルの IP アドレスでアクセス出来ていたのですが、今スマホは Wifi に接続されていません。

筆者が雑に作ったイメージ図です。イメージ図です。(大事なことなので)

オンプレでの実行時はこんな感じです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/248829/6840319d-e8f7-b203-a0be-04360483a574.png)

IP アドレスからスマホ君がどこへアクセスしたいのかをお家の Wifi を管理してくれてる機器がうまく制御してくれます。

次に、Wifi から外した時のイメージ図です。イメ(ry

![](https://storage.googleapis.com/zenn-user-upload/6067kqi0rf035sel45kdi77kxsj1)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/248829/8bdbe134-3f98-4a3a-746f-383551c90138.png)

ここで問題なのは、この IP アドレスはローカルなネットワークでしか理解できないものですので、異なるネットワークから接続しようとしてもどこにあるのか分かりません。東京のおまわりさんに奈良の住所を聞いても場所のイメージがつかないようなものです(?) なお、実際にはサーバーに繋がろうとスマホ君が頑張っていたことすら、サーバー君には届きません。

逆に言うと、何等かの方法で別のネットワークからでもアクセスできるところにサーバー君がいれば、スマホ君からアクセスができますね。



![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/248829/4ce5479f-8cfc-30e9-dd2a-0ef0be14fd90.png)


このことから、**Web アプリを作成した際にはアプリの公開方法を意識する必要がある**ということが分かりますね。例えば、自社の人のみが使用する Web アプリであれば自社のネットワークにいたらアクセスできることが目的になるかもですが、一般の人が利用するアプリ等であればインターネット等で接続できるようにしなければいけません。

今回はその解決策の一つとして、クラウドサービスを使います。

# Azure 使う
いよいよクラウドを使います。「ここまで長かったな。。。」って思った方もいらっしゃるかと思いますが、あと一息ですので一緒にがんばりましょう。僕も書いてて疲れてきましたががんばります。

## リソース作成
Azure に作成したアカウントでログインして、Portal の上の検索バーで「App Service」って検索して、新規に App Service のリソースを作成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/248829/bebe0d56-e477-59c6-5981-b03e56a592f9.png)

公開、ランタイム スタック、オペレーティング システムは以下に揃えてもらうと確実かなと思います。
![](https://storage.googleapis.com/zenn-user-upload/p09njhrhgg0wiytoakceyoq9gcef)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/248829/3a4a05b0-aece-56c6-bf47-f9c8d29012c8.png)

リソース名やリソースグループ等はご自由に編集してください。そしたら、作成まで進めてください。

## Deploy
先ほど作ったリソースに対して作成したアプリを Deploy します。もし気になる方は以下も参考にしてください。

https://docs.microsoft.com/ja-jp/azure/app-service/quickstart-nodejs?pivots=platform-windows

VSCode でプロジェクト一式を開きましょう。先ほど npm start 等のコマンドを入力した時のように、
Powershell 等で該当のディレクトリ(フォルダ階層) にいる場合は以下のコマンドでも開けます。

```
code .
```

(Code は VSCode のコマンド、"." は現在のディレクトリのファイル全てを指定しているイメージです。)

もしなんらかの理由でコマンドが実行できない人は以下のようにVSCode を開いてからフォルダを指定して開いてください。
![](https://storage.googleapis.com/zenn-user-upload/2kddglvl494554hj46i3qn66ylx6)![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/248829/1db488d7-0bf7-0f1f-162b-2168840d2064.png)


左側から、追加した Azure の拡張機能をクリックして、画像のように作成した App Service のリソースを見つけます。サブスクリプション等があっているかを確認して探しましょう。(最初は Azure へのログイン等も要求されるかと思います。)


![](https://storage.googleapis.com/zenn-user-upload/yskl8hqrbz15ukaln1s8e0bwf9jg)![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/248829/063bb781-4f43-c973-231c-28b40cd76d62.png)


そこで右クリックをして「Deploy to Web App...」 を実行します。
![](https://storage.googleapis.com/zenn-user-upload/cksc30ifquqzhpprbeybjmig0x56)![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/248829/2aba9578-3fbb-0c71-cbd0-aa232abadbb4.png)


その後、 Deploy するか等の確認がされますので従ってクリックをして Deploy 完了まで待ちましょう。

## App Service 上の Web アプリにアクセスする
さて、Deploy が完了したらいよいよ大詰めです。実際に App Service に Deploy したアプリにアクセスしてみましょう。

該当の App Service リソースを開くと、以下のように URL の欄があるのでこちらをクリックしてもらうと
![](https://storage.googleapis.com/zenn-user-upload/telozx6fwpac82xfyfwvd6ob0m8z)![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/248829/c53a1641-32c9-85d7-0925-8bce1caf1fc3.png)


先ほどローカルで実行していたページを同じページが開けます。
![](https://storage.googleapis.com/zenn-user-upload/e5h18jht5qyt6rxs69pag0mk54ra)![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/248829/f24a121b-864f-f8ed-3d0a-e76e57b4ee28.png)


他のエンドポイントに関しても以下の通り！
![](https://storage.googleapis.com/zenn-user-upload/9dbnwq9x87zntukangzuegk45znf)![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/248829/4e56ee9f-2cc2-4eba-b490-3bebbd3cbdcc.png)


## スマホからアクセス
今度は**スマホのWi-Fi をオフにして** App Service へアクセスしてみましょう。ローカルで実行していた時にはアクセスできなかったのが、アクセスできているのではないでしょうか。

![](https://storage.googleapis.com/zenn-user-upload/4b676rqa2b6w0l5ytelj31xa3njk)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/248829/38435adc-cd62-af74-0016-b869214f6c33.png)

こんな風に**パブリックにアクセスできる(異なるネットワークからアクセスできる)リソースを用意できる**のはクラウドの魅力の一つかと思います。(この一文のためにかなり回り道をしました)

## HTML 編集
こちらは任意ですが、ローカルの時同様に HTML を編集したい場合には、以下の App Service Editor を使用できます。実際には、こちらはプレビュー機能であるためお勧めはできませんが、そもそも本来は**開発はローカルで行って、エラー等が出ない状態にしてから クラウドへ Deploy **というイメージが多いかなとかと思います。(CI/CD とかそういう話は抜きにしてます。)

![](https://storage.googleapis.com/zenn-user-upload/u0a0s5fmklscrr0q9vyp6ssdfvr4)![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/248829/3daf1642-20a1-ca25-a9ca-e52db354b080.png)


## クラウドに POST
念のために POST も試してみましょう。ローカルの際と同様に .http ファイルから POST リクエストを送ってみましょう。

先ほどは http://localhost:3978/test-post だったかと思いますが、今回は先ほどの https://<App Service Name>.azurewebsites.net/test-post に対してリクエストを送ってみて、先ほどと同様の動作を確認してみてください。
	



# まとめ
今回はクラウドを体験しやすいものとして、サーバアプリ(node.js 製)をローカルとクラウドのどちらでも実行してみるハンズオンとしてみました。もちろん、クラウドの利点は他にもたくさんありますが、イメージの一端でも伝わってますと幸いです。

クラウドのメリットとして今回の例では、クラウドを使うとサーバーアプリにアクセスしやすかったり、手元でサーバを起動する時のように常に手元の PC でサーバアプリを起動する必要等がない点がありましたが、実際にはそもそも個人手では開発が難しい機能等をクラウドを利用すると開発のハードルが低くなるといったケースもあります。

ただ、オンプレミスの方が良い場合等もあるかと思います。今回のハンズオンでいうと誤差の範囲化と思いますが、ネットワークの距離的な問題から処理の速度がオンプレの方が早いこともあります。また、社外につなげないような環境であればオンプレの環境の方が良いこともあります。

結局のところ、技術に至高なんてものは存在しないのかなと思います。ベストプラクティスなんて状況に応じて変化すると思います。なので、クラウドやオンプレ等の単語で反応して否定するよりは、それぞれの強みを理解して状況に応じて使い分けるのが大切なのかもしれませんね。(雑なまとめ)

とりあえず、僕としては皆さんが楽しく学習出来たら良いなって思ってます。では。