- 投稿日:2020-08-17T19:54:09+09:00
webpackをかんたんに使う(Zero Configulation)
5年前の記事のメンテを行っていたんですが、流石にBrowserifyは実務で使う可能性は低いよなあとは思います。
Browserifyの単純さも初心者にはとっつきやすいのですが、今の主流はwebpackです。
webpack入門記事はたくさんあるはずですが、設定ファイルの各パラメータの羅列だったり、BabelやReact, TypeScriptの設定まで一気に済ませてしまうような記事は初心者には難しいかもしれないですね。というわけで、Node.jsは3日前にはじめました、みたいな人向けに書いてみようと思います。
初心者なのでwebpackだけを使ってみたいんだけど
今どきだと初心者はReactならcreate-react-app、VueならVue CLIを使って入門するんじゃないかと思います。これらはwebpackの設定を代わりに済ませてくれる便利なツールで、難しいことを知らなくて済みます。
ただ、何も理解しないままにWebアプリが作れてしまうので、一つ一つ理解していきたいタイプの人には気持ちが悪いかもしれません。
というわけで、webpackのみを使ってWebアプリを作ってみましょう。
プロジェクトを作成
下記のコマンドを実行してpackage.jsonを作ります。
npm init -y次にnode_modules下にwebpackと開発ツールをインストールします。
npm install -D webpack webpack-cli webpack-dev-serverその結果、下記のようなpackage.jsonが生成されます。
{ "name": "your-folder", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [], "author": "", "license": "ISC", "devDependencies": { "webpack": "^4.44.1", "webpack-cli": "^3.3.12", "webpack-dev-server": "^3.11.0" } }ソースコードを配置する
下記の2ファイルを作成してください。
- dist/index.html
- src/index.js
//index.js document.write("Hello, webpack")<!-- index.html --> <!DOCTYPE html> <html> <head> <title>Hello</title> </head> <body> <script src="main.js"></script> </body> </html>結果、下記のようなフォルダ構成になります。
webpackを動かすには色々設定が必要ですが、無設定の場合は
src/index.js
が入り口になります。dist
はwebpackが処理した後のjsファイルが出力されます。上記のフォルダ構成にしておけば無設定でも動かせるわけです。npm-scriptsを追加
開発は
npm run dev
、ビルドはnpm run build
で行えるようにしましょう。package.json内にwebpackの実行時に渡すオプションを直書きしていきます。
package.json
のscripts
にbuild, devの2行を追加します。"scripts": { "test": "echo \"Error: no test specified\" && exit 1", "build": "webpack --mode=production", "dev": "webpack-dev-server --hot --open --content-base dist/" },実行してみる
下記のコマンドを実行してみましょう。
npm run devブラウザが開いて
Hello, webpack
が表示されればOKです。npmのライブラリを使ってみる
今回は日時処理ライブラリ
date-fns
を使ってみましょう。
下記のコマンドを実行してください。npm install -D date-fns次に、index.jsの内容を下記のように書き換えてください。
//index.js const dateFns = require("date-fns") const ja = require("date-fns/locale/ja") document.write(dateFns.format(new Date(), "'今日は' MMM do iiii", {locale: ja.default}))その後、
npm run dev
をもう一度実行してみてください。こんな表示になりましたでしょうか。
webpackはjsを張り合わせる糊
webpackにはいろんな機能がありますが、一番基本的な機能はjsの結合処理です。今回の場合は
index.js
とdate-fns
ライブラリが張り合わせられて、一本のjsファイルにまとめられています。
npm run build
を実行後、dist/main.js
を開くと、結合されたjsファイルを見ることができます。
※npm run dev
実行時にはmain.js
は出力されません。これはwebpack-dev-server
というツールの機能で、ブラウザからはmain.jsがあるように見える状態になっています。webpackが何をしているのか、詳細を知りたい方は下記記事がおすすめです。
https://mizchi.hatenablog.com/entry/2018/11/26/164523
終わりに
この状態ではかなりできることが限られていて、例えばReactのJSXファイルやVue SFC, TypeScriptファイル等を読ませてもエラーになります。
BabelやTypeScriptの設定に進みたい方は下記記事を参考にしてください。https://qiita.com/clockmaker/items/8620cf6bd99d810dbf2a
あるいは、ここまでで概要を把握できたら、もうcreate-react-appやVue CLIを使っても良いでしょう。
個人的にはParcelをよく使っていて、今後はviteに移行する予定です。
- 投稿日:2020-08-17T13:49:06+09:00
Vue 3.0とgRPCを使ってTodoListを作ってみた
gRPCとは?
gRPCはオープンソース、RPCフレームワークをベースとして、最初はGoogleが開発されました。
インターフェース記述言語としてProtocol Buffersを使用し、protobufは構造化データをシリアル化するためのメカニズムです。
protoファイルでサービスとそのデータ構造を定義するだけで、gRPCがさまざまな言語でプラットフォームのクライアントとサーバーのStubsを自動的に生成します。
profobufを使用すると、JSONではなくバイナリを使用して資料を転送しています。
これにより、gRPCがはるかに高速で信頼性の高いものになります。
gRPCの他の主要な機能のいくつかは、双方向ストリーミングとフロー制御、BlockingまたはNonBlockingバインディング、および認証機能です。
gRPCはHTTP/2を使用して、シングルTCPコネクションの中で複数のストリームを開始することができます。
gRPCの詳細については、こちらをご覧ください:https://grpc.io/gRPC V.S. REST
Feature gRPC REST Portocol HTTP/2 (早い) HTTP/1.1 (遅い) Payload Protobuf (バイナリ、小さい) JSON (テキスト、大きい) API構造 厳格、必要 (.proto) ゆるい、選択 Code生成 内蔵 (protoc) 他のツール (Swagger) 安全性 TLS/SSL TLS/SSL ストリーミング 双方向ストリーミング クライアント -> サーバーリクエストだけ ブラウザのサポート 制限あり (grpc-webは必要) ほぼ全部 Protobuf と gRPC を使えば、REST API の GET、PUT やヘッダーなどを気にする必要はありません、そしてgRPCフレームワークによって生成されたStubsにはデータモデル用の記述が全部書いてるので、直接引用するだけで使えます。
開発環境とツール
- Protoc v3.12.4 -- Protobuf コンパイラー Stubs を生成する為に使ます。
- Node.js v14.2.0 -- バックエンドとVueのビルドに使います。
- Docker v19.03.12 -- envoyを動かす為に使ます。
- envoy v1.14 -- 普通WebからのHTTP/1.1をHTTP/2に変換する為のプロキシ。
- Vue.js 3.0.0-rc.5 -- 今回は Vue 3 を使ってフロントエンドを作成します。
- Docker Compose v1.26.2 -- 全部をDocker化する為に使います、なくでも動けます。
フォルダ構成
全体の流れ
- Protoファイルの作成
- Node.jsでバックエンド作成
- Envoy proxyの設定
- Client stubsの生成
- Clientの作成
- 動かしてみましょう
- Docker化
コードを書いてみましょう
1. Protoファイルの作成
ProtoファイルはgRPCの心臓と呼ばれる部分、ここでRequestとResponseとサービスを定義することによって、後でStubsファイルを自動的に生成することができます。
Protoファイルの構成は大体四つの部分に分けている。
1. Protoのバージョンを定義する
2. Packageの名前
3. サービス定義
4. メッセージ定義todo.protosyntax = "proto3"; package todo; service todoService { rpc addTodo(addTodoParams) returns (todoObject) {} rpc deleteTodo(deleteTodoParams) returns (deleteResponse) {} rpc getTodos(getTodoParams) returns (todoResponse) {} } // Request message getTodoParams{} message addTodoParams { string task = 1; } message deleteTodoParams { string id = 1; } // Response message todoObject { string id = 1; string task = 2; } message todoResponse { repeated todoObject todos = 1; //ここはArrayの中身にtodoObjectが複数ありますのこと。 } message deleteResponse { string message = 1; }2. Node.jsでバックエンド作成
環境設定:
npm:
bashnpm init -y npm i uuid grpc @grpc/proto-loader npm i -D nodemonyarn:
bashyarn init -y yarn add uuid grpc @grpc/proto-loader yarn add -D nodemonstartのnodeをnodemonに書き換える:
package.json{ "name": "server", "version": "1.0.0", "description": "A Node.js gRPC API Server", "main": "server.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "start": "nodemon server.js" }, "author": "", "license": "MIT", "devDependencies": { "nodemon": "^2.0.4" }, "dependencies": { "@grpc/proto-loader": "^0.5.5", "grpc": "^1.24.3", "uuid": "^8.3.0" } }サーバーのコード内容:
server.js// proto ファイルのパス const todoProtoPath = './todo.proto'; // npm packageを導入 const grpc = require('grpc'); const protoLoader = require('@grpc/proto-loader'); const { v4: uuidv4 } = require('uuid'); // grpcの初期化 const packageDefinition = protoLoader.loadSync( todoProtoPath, { keepCase: true, longs: String, enums: String, defaults: true, oneofs: true, }, ); // packageを指定 const todoProto = grpc.loadPackageDefinition(packageDefinition).todo; // Todosの保存、リースダートしたら資料が消えます let Todos = []; const addTodo = (call, callback) => { const todoObject = { id: uuidv4(), task: call.request.task, }; console.log(call.request); Todos.push(todoObject); console.log(`Todo: ${todoObject.id} added!`); callback(null, todoObject); }; const getTodos = (call, callback) => { console.log('Get tasks'); console.log(Todos); callback(null, { todos: Todos }); }; const deleteTodo = (call, callback) => { Todos = Todos.filter((todo) => todo.id !== call.request.id); console.log(`Todo: ${call.request.id} deleted`); callback(null, { message: 'Success' }); }; const getServer = () => { const server = new grpc.Server(); // サービスを登録、名前はprotoファイルと同じなので省略できます server.addService(todoProto.todoService.service, { addTodo, getTodos, deleteTodo }); return server; }; if (require.main === module) { const server = getServer(); server.bind('0.0.0.0:9090', grpc.ServerCredentials.createInsecure()); server.start(); console.log('Server running at port: 9090'); }3. Envoy proxyの設定
Envoy proxyはサーバーとクライアントの中央にいるサービスです、主にはHTTP/1.1のコネクションをHTTP/2に変換するの役割です。
Dockerのイメージ設定ファイル
DockerfileFROM envoyproxy/envoy:v1.14-latest COPY ./envoy.yaml /etc/envoy/envoy.yaml CMD /usr/local/bin/envoy -c /etc/envoy/envoy.yamlEnvoyの設定ファイル
envoy.yamladmin: access_log_path: /tmp/admin_access.log address: socket_address: { address: 0.0.0.0, port_value: 9901 } static_resources: listeners: - name: listener_0 address: socket_address: { address: 0.0.0.0, port_value: 8080 } filter_chains: - filters: - name: envoy.filters.network.http_connection_manager typed_config: "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager stat_prefix: ingress_http codec_type: AUTO route_config: name: local_route virtual_hosts: - name: local_service domains: ["*"] routes: - match: { prefix: "/" } route: cluster: todo_service max_grpc_timeout: 0s cors: allow_origin_string_match: - prefix: "*" allow_methods: GET, PUT, DELETE, POST, OPTIONS allow_headers: keep-alive,user-agent,cache-control,content-type,content-transfer-encoding,custom-header-1,x-accept-content-transfer-encoding,x-accept-response-streaming,x-user-agent,x-grpc-web,grpc-timeout max_age: "1728000" expose_headers: custom-header-1,grpc-status,grpc-message http_filters: - name: envoy.filters.http.grpc_web - name: envoy.filters.http.cors - name: envoy.filters.http.router clusters: - name: todo_service connect_timeout: 0.25s type: logical_dns http2_protocol_options: {} lb_policy: round_robin load_assignment: cluster_name: cluster_0 endpoints: - lb_endpoints: - endpoint: address: socket_address: # docker-composeを使うときserverに書き換えます address: host.docker.internal port_value: 9090gRPCサービスは9090 portで動かして、Envoyは8080 portでWebからのHTTP/1.1をHTTP/2に変換して9090に送るそいう仕組みです。
4. Client stubsの生成
protocをインストール : Protocol Buffer Compiler Installation
bash# Linux $ apt install -y protobuf-compiler $ protoc --version # MacOS using Homebrew $ brew install protobuf $ protoc --version先にVueのProjectを作成します。
vue-cliを使います。bashvue create clientそしてStubsを作ります
このコメンドで ./client/src に二つのJSファイルを生成する
- todo_pb.js // メッセージのType定義
- todo_grpc_web_pb.js // gRPCクライアント
bashprotoc -I server todo.proto \ --js_out=import_style=commonjs,binary:client/src \ --grpc-web_out=import_style=commonjs,mode=grpcwebtext:client/src5. Clientの作成
クライアントのTodoコンポーネントの中にtodo_pb.jsとtodo_grpc_web_pb.jsを導入して、todoServiceClient()を使ってlocalhost:8080のEnvoy proxyに接続します。
Todo.vueimport { ref } from 'vue' // クライアントが使う部分だけを導入する import { getTodoParams, addTodoParams, deleteTodoParams } from "../todo_pb.js"; import { todoServiceClient } from "../todo_grpc_web_pb.js"; import CloseIcon from './CloseIcon' export default { components:{ CloseIcon }, setup() { const todos = ref([]) const inputField = ref('') // 新しクライアントのインスタンスを作成 const client = new todoServiceClient("http://localhost:8080", null, null); const getTodos = () => { let getRequest = new getTodoParams(); client.getTodos(getRequest, {}, (err, response) => { if (err) console.log(err); console.log(response.toObject()); todos.value = response.toObject().todosList; }); } getTodos() const addTodo = () => { let addRequest = new addTodoParams(); addRequest.setTask(inputField.value); client.addTodo(addRequest, {}, (err) => { if (err) console.log(err); inputField.value = ""; getTodos(); }); } const deleteTodo = (todo) => { let deleteRequest = new deleteTodoParams(); deleteRequest.setId(todo.id); client.deleteTodo(deleteRequest, {}, (err, response) => { if (err) console.log(err); if (response.getMessage() === "Success") { getTodos(); } }); } return { todos, inputField, addTodo, deleteTodo } } }完成の参考 : Github
6. 動かしてみましょう
Back-Endを立ち上げて:
bash$ cd ./server $ npm startenovy proxy:
bash$ docker build -t envoy:v1 ./enovy $ docker run --rm -it -p 8080:8080 envoy:v1Front-End:
bash$ cd ./client $ yarn dev7. Docker化
Docker Compose一発で動かす為にDocker化します。
各フォルダにDockerfileと.dockerignore入れます。./serverフォルダ
DockerfileFROM node:lts-alpine # make the 'app' folder the current working directory WORKDIR /app # copy both 'package.json' and 'package-lock.json' (if available) COPY package*.json ./ # install project dependencies RUN npm install # copy project files and folders to the current working directory (i.e. 'app' folder) COPY . . EXPOSE 9090 CMD [ "node", "server.js" ].dockerignore.git .gitignore node_modules README.md./clientフォルダ
DockerfileFROM node:lts-alpine # install simple http server for serving static content RUN npm install -g http-server # make the 'app' folder the current working directory WORKDIR /app # copy both 'package.json' and 'package-lock.json' (if available) COPY package*.json ./ COPY yarn.lock ./ # install project dependencies RUN yarn install # copy project files and folders to the current working directory (i.e. 'app' folder) COPY . . # build app for production with minification RUN yarn run build EXPOSE 3000 CMD [ "http-server", "-p", "3000", "dist" ].dockerignore.git .gitignore node_modules README.md./docker-composer.ymlを作成します。
docker-compose.ymlversion: '3' services: web: build: ./client image: todo-grpc-vue-client:v1 ports: - 3000:3000 restart: unless-stopped networks: - grpc-todolist proxy: build: ./envoy image: todo-grpc-envoy:v1 ports: - 8080:8080 restart: unless-stopped networks: - grpc-todolist server: build: ./server image: todo-grpc-server:v1 restart: unless-stopped networks: - grpc-todolist networks: grpc-todolist: driver: bridgeEnvoyの設定ファイルのサーバーアドレス修正します
envoy.yamlendpoints: - lb_endpoints: - endpoint: address: socket_address: # host.docker.internalをserverに書き換える address: server port_value: 9090そしてビルドして立ち上げます。
bash# イメージをビルド $ docker-compose build # 特定のイメージをリビルドします $ docker-compose build --no-cache [service] # 立ち上げる $ docker-compose up # 背景で立ち上げる $ docker-compose up -d # ログを確認 $ docker-compose logsFront-Endに入ります:http://localhost:3000
最後
Qiitaで初めての投稿です、よろしくお願いします。
Githubでソースコードを公開しています、
なんが詰まったところがあれば参考してください:Github
- 投稿日:2020-08-17T11:28:42+09:00
Visual Studioのコードと同じDockerを使ってNode.jsアプリを開発する
このガイドでは、Ubuntu Linuxデスクトップ上でVisual Studio Codeを使ってNode.jsアプリを開発し、Alibaba Cloud上でDockerを使って同じアプリをデプロイしていきます。
本ブログは英語版からの翻訳です。オリジナルはこちらからご確認いただけます。一部機械翻訳を使用しております。翻訳の間違いがありましたら、ご指摘いただけると幸いです。
よくある質問
Node.jsとは?
Node.jsはオープンソースでクロスプラットフォームなJavaScriptのランタイム環境で、サーバー上でJavaScriptを実行することができます。
Express とは?
Expressは、最小限で柔軟性の高いNode.jsのWebアプリケーションフレームワークで、Webとモバイルアプリケーションのための堅牢な機能セットを提供しています。
Dockerとは?
Dockerは非常に人気のあるコンテナプラットフォームで、アプリケーションやサービスを簡単にパッケージ化、デプロイ、消費することができます。
Docker Hubとは?
Docker Hubは、Dockerユーザーやパートナーがコンテナイメージを作成、テスト、保存、配布するクラウドベースのリポジトリです。
Visual Studio Codeとは?
Visual Studio Codeは、デスクトップ上で動作し、Windows、MacOS、Linuxに対応した軽量かつ強力なソースコードエディタです。JavaScript、TypeScript、Node.jsをビルトインでサポートしており、他の言語(C++、C#、Java、Python、PHP、Goなど)やランタイム(.NET、Unityなど)に対応した拡張機能の豊富なエコシステムを備えています。Visual Studio Codeでは、Dockerを使ったアプリケーションのデプロイを簡単に行うことができ、プロジェクトの種類に応じて適切なDockerファイルの生成と追加をサポートしています。
Alibaba Cloud Simple Application Serverとは?
Simple Application Serverは、アプリケーションの起動と管理、ドメイン名解決の設定、ウェブサイトの構築、監視、保守を数回クリックするだけで行えるオールインワンのソリューションを提供します。プライベートサーバーの構築が格段に簡単になり、初心者がアリババクラウドを始めるのに最適な方法です。
アプリケーションの開発例
Ubuntu Linuxデスクトップに前提条件をインストール
私はバージョン16.04のUbuntu Linuxデスクトップを持っています。記載されている手順は、すべてのバージョンでほとんど同じです。
Node.js
node.jsが既にインストールされているかどうかを確認します。
node –vバージョン番号が表示されない場合は、以下の手順でインストールしてください。
sudo apt-get install curl python-software-properties curl -sL https://deb.nodesource.com/setup_12.x | sudo -E bash – sudo apt-get install nodejsノードとnpmのバージョンを確認します。
node –v npm –vDocker
DockerにはEnterprise版とCommunity版があります。今回はコミュニティ版のDocker CEをインストールします。
以前のバージョンがインストールされているかどうかを確認し、インストールされている場合はアンインストールしてください。
sudo apt-get remove docker docker-engine docker.io containerd runcaptパッケージを更新します。
sudo apt-get updateaptがHTTPSでリポジトリを使用できるようにします。
sudo apt-get install \ apt-transport-https \ ca-certificates \ curl \ gnupg-agent \ software-properties-commonGPGキーを追加
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add –安定版リポジトリを設定してインストールします。
sudo add-apt-repository \ "deb [arch=amd64] https://download.docker.com/linux/ubuntu \ $(lsb_release -cs) \ stable"dockerをインストールします。
sudo apt-get update sudo apt-get install docker-ce docker-ce-cli containerd.iohello-worldイメージを実行して、Dockerが正しくインストールされているかどうかを確認します。
sudo docker run hello-worldこのコマンドはイメージをダウンロードしてコンテナ内で実行し、そのコンテナ内でHello Worldを印刷します。
しかし、上記のコマンドはsudoまたはrootユーザのアクセスで実行されています。
次にインストールするVisual Studio CodeとそのDockerエクステンションをIDEとして使用する予定なので、非rootユーザで実行できるようにする必要があります。VS Codeは非rootユーザで動作し、拡張機能を使うことでコンテナ化されたアプリケーションの構築、管理、デプロイが容易になります。
Dockerグループを作成します。
sudo groupadd dockerユーザーをdockerグループに追加します。
sudo usermod -aG docker $USERログアウトして再度ログインするか、グループのメンバーシップが再評価されるように再起動してください。
sudo reboot再起動後、sudoなしでdockerコマンドが実行できることを確認します。
docker run hello-worldVisual Studioコード
VS Code をインストールする最も簡単な方法は、Snap パッケージとしてインストールすることです。スナップはすべての主要な Linux ディストリビューションで使用することができ、ほとんどの Ubuntu デスクトップにプリインストールされています。もしあなたのデスクトップにない場合は、https://docs.snapcraft.io/installing-snapd からインストールすることができます。
VSコードをインストールします。
sudo snap install --classic codeアプリケーション/プログラミングから同じものを選択するか、linuxターミナルでコードを入力してVisual Studioのコードを開きます。
「表示」→「拡張機能」に移動します。
Docker」を検索して、拡張機能をインストールします。拡張機能の詳細は https://marketplace.visualstudio.com/items?itemName=ms-azuretools.vscode-docker を参照してください。
Node.jsプロジェクトの作成
アプリケーション/プログラミングから同じものを選択するか、linuxターミナルでコードを入力してVisual Studioのコードを開きます。
フォルダを開くを選択し、documentsディレクトリに移動します。ここでプロジェクトを作成します。
VS Codeにはシェルコマンドを実行するためのターミナルが統合されています。そこから直接Node.jsを実行することができます
Visual Studio Code のトップメニューから Terminal -> New Terminal を選択して Terminal を開きます。
Express用のテンプレエンジンをインストールするためにExpress Generatorをインストールします。
sudo npm install -g express-generator新しいエクスプレスアプリケーションを足場にします。
express nodeexpress-alibaba-docker-tutorial --view=pugこれにより、nodeexpress-alibaba-docker-tutorialという名前の新しいフォルダが作成され、左のdocumentsの下にあるアプリケーションの内容を見ることができます。
コードの編集と変更
ここに独自の開発コードを追加します。ここでは、いくつかの簡単な変更を行います。
routes フォルダの下にある index.js を選択します。
index.jsの中のres.renderを含むコードの行に移動します。
以下のように変更してください。
res.render('index', { title: 'Docker on Simple Application Server', data:'Alibaba Cloud' });フォルダビューの下にあるindex.pugを選択します。
Welcome to
を含む行のデータ
にタイトル
を変更します。アプリケーションの実行
VSCodeターミナルで、ディレクトリをアプリケーションフォルダに変更します。
cd nodeexpress-alibaba-docker-tutorialpackage.jsonファイルに存在するアプリケーションの依存関係をインストールします。
npm installPackage.jsonファイルには、Node.jsアプリケーションを実行するためのスタートスクリプトも含まれています。
npm startブラウザを開き、localhost:3000にアクセスしてアプリケーションを表示します。ポート番号はスタートスクリプトから呼び出されるbinフォルダ内のファイルwwwの中に設定されています。
Visual Studio Codeのトップメニューから「ファイル」→「フォルダを閉じる」を選択し、VS Codeでアプリケーションを閉じます。
アプリケーションのDockerize例
パブリックリポジトリは、誰もが利用できるDockerイメージをホスティングするために使用することができます。Docker hubはパブリックリポジトリであり、利用するためのパブリックなDockerイメージのリストを見つけることができます。あとはそれらのイメージを引っ張ってきて、それを元にコンテナを起動し始めるだけです。Docker Hub上の公開リポジトリに公開することで、イメージを利用可能にしています。
Docker Hubアカウントとリポジトリの作成
https://hub.docker.com/ にサインアップし、アカウントを作成したらログインします。
トップメニューからリポジトリを選択します。
アカウントを作成したばかりなので、リポジトリはありません。リポジトリの作成ボタンを選択してリポジトリを作成します。これがあなたの画像が保存されるリポジトリです。
次の画面では、リポジトリの名前と説明を指定します。ここでは下の画像のようにnodeexpress-alibaba-docker-tutorialという名前を指定します。
リポジトリを公開し、dockerhub上で検索できるようにしています。また、リポジトリを非公開にすることもできます。1つのプライベートリポジトリは無料で、課金プランを利用すればそれ以上の数のリポジトリを作成することができます。プライベートリポジトリは公開リポジトリと同じように動作しますが、閲覧や検索ができません。
Click on the Create button and your repository is ready.
画面の右端にあるコマンドに注目してください。このコマンドを実行して画像をこのリポジトリにプッシュする必要があります。
画像は
[registry or username]/[image name]:[tag]
の形式である必要があります。注:Alibaba Cloudは、https://www.alibabacloud.com/product/container-registry で利用できる安全なコンテナレジストリも提供しています。
アプリケーションをDockerizeする
フォルダを開くを選択し、documentsフォルダの下にあるnodeexpress-alibaba-docker-tutorialフォルダに移動し、アプリケーションを開きます。
Visual Studio Codeのトップメニューから「ターミナル」→「新規ターミナル」を選択してターミナルを開きます。
Dockerがインストールされて実行されていることを確認します。
docker –versionVisual Studio CodeのトップメニューからView->Command Paletteを選択してCommand Paletteを開きます。
ワークスペースにDockerファイルを追加と入力し、Dockerを選択して実行します。Dockerファイルをワークスペースに追加するコマンドを実行します。
コマンドパレットでアプリケーションプラットフォームの選択を求められますので、Node.jsを選択します。
また、アプリケーションがリスンするポートを指定します。
これにより、ソースファイルの場所やコンテナ内でアプリを起動するコマンドなど、アプリの環境を記述するDockerfileと共にプロジェクトに特定のファイルが追加されます。
コマンドパレットでDocker: Build Imageを実行してイメージをビルドします。先ほど作成したDockerfileを選択し、Docker hubリポジトリの作成時に指定したフォーマットでイメージに名前を付けます。名前は.........
arnab74/nodeexpress-alibaba-docker-tutorial:firsttry
ターミナルパネルが開き、Dockerコマンドが実行されます。ビルドが完了すると、DockerエクスプローラーのImagesの下にイメージが表示されます。
コマンドパレットでdocker runと入力し、Docker:Images runを選択してコンテナをビルドします。
コマンドパレットで、イメージグループ
arnab74/nodeexpress-alibaba-docker-tutorial
を選択します。コマンドパレットで、Image firsttryを選択します。
ターミナルに表示された生成されたコマンドを実行します。
コマンドは'docker run'で、2つのフラグがあります。
-p : これはコンテナ上のポートを公開し、ホスト上のポートにマッピングします。ここでマッピングされたホスト上のポートも同様に3000です。
-d : バックグラウンドでコンテナを実行します。
詳細は https://docs.docker.com/engine/reference/commandline/run/ を参照してください。
実行中のコンテナを検査します。
Docker psブラウザを http://your_server_ip:3000 または http://localhost:3000 に移動してアプリケーションを表示します。
実行中のアプリケーションコンテナを停止するには、実行中のコンテナを右クリックして、DOCKER explorer の Containers の下にある stop を選択します。
または、ターミナルで以下のコマンドを実行することができます。
docker stop [CONTAINER ID]CONTAINER ID]を
Docker ps
コマンドで取得した自分のCONTAINER IDに置き換えてください。お試し追加ステップ
VSCode の docker 拡張機能によって自動的に生成される dockerfile を改良しました。
https://hub.docker.com/_/node/ から現在の nodejs LTS バージョンに基づいてアプリケーションのベースイメージを更新します。
コンテナをrootで実行することは避けなければなりません。Docker Nodeイメージには、rootではないノードのユーザが含まれています。ユーザーと同じにして、そのホームディレクトリを作業ディレクトリに設定します。
新しいDockerfileは以下のようになります。
FROM node:10.16-alpine ENV NODE_ENV production RUN mkdir -p /home/node/app/node_modules && chown -R node:node /home/node/app WORKDIR /home/node/app COPY ["package.json", "package-lock.json*", "npm-shrinkwrap.json*", "./"] USER node RUN npm install --production --silent && mv node_modules ../ COPY --chown=node:node . . EXPOSE 3000 CMD npm start前述のプロセスに従って、新しいイメージをビルドし、
arnab74/nodeexpress-alibaba-docker-tutorial:latest
という名前で実行してテストします。Docker Hubに画像をアップロードする
Docker Explorerで、レジストリセクションのConnect Registryを選択します。
利用可能なオプションで、レジストリプロバイダとしてDocker Hubを選択します。
ユーザー名とパスワードを入力してログインします。
コマンドパレットでdockerタグを書き、Docker Images:Tagを選択します。
次のコマンドパレット画面で画像グループを選択します。
arnab74/nodeexpress-alibaba-docker-tutorial次の画面でタグ付けする画像を選択
latest新しいタグを提供
arnab74/nodeexpress-alibaba-docker-tutorial:0.1コマンドパレットでdocker pushを書き、Docker Images:Pushを選択します。
次のコマンドパレット画面で画像グループを選択します。
arnab74/nodeexpress-alibaba-docker-tutorial次の画面でDocker hubにプッシュするImageを選択します。
0.1ターミナル上にDocker Pushコマンドが生成されるので、それに従ってください。
以下のようにターミナル上で上記の手順を行うこともできます。
docker login --username=arnab74 docker images docker tag [IMAGE ID] arnab74/nodeexpress-alibaba-docker-tutorial:0.2IMAGE ID を最新のタグ付けされた画像の画像 ID に置き換えてください。
docker push arnab74/nodeexpress-alibaba-docker-tutorial:0.2アップロードされた画像は、Docker hubのサイトのリポジトリやDocker Explorerのレジストリで確認できるはずです。
シンプルなアプリケーションサーバにアプリケーションをデプロイする
並行記事Developing Node.js App in Visual Studio and Deploying on Simple Application Serverをご覧いただき、Alibaba Cloud上にCentOS7でSimple Application Serverインスタンスを作成し、インスタンスへのパスワードを作成し、デスクトップ端末を使ってログインする方法をご紹介します(記事のようにputtyではなく)。
サーバーに前提条件をインストールする
yum
yumは、CentOSでソフトウェアパッケージを取得、インストール、削除、クエリ、管理するための主要なツールです。まず、ソフトウェアリポジトリを最新のバージョンにアップデートするために使います。
yum -y updateDocker
古いバージョンがある場合は、アンインストールしてください。
sudo yum remove docker \ docker-client \ docker-client-latest \ docker-common \ docker-latest \ docker-latest-logrotate \ docker-logrotate \ docker-engine必要なパッケージをインストールします。
sudo yum install -y yum-utils \ device-mapper-persistent-data \ lvm2インストールするリポジトリの設定
sudo yum-config-manager \ --add-repo \ https://download.docker.com/linux/centos/docker-ce.repoDockerのインストール
sudo yum install docker-ce docker-ce-cli containerd.ioDockerの起動
sudo systemctl start dockerDockerを非rootユーザーで動作させます。
sudo groupadd docker sudo usermod -aG docker $USER sudo reboot Start Docker againsudo systemctl start dockerコマンドが sudo なしで実行されているかどうかを確認します。
docker run hello-worldアプリケーションのデプロイ
コンテナをビルドしてアプリケーションを実行します。マシンのローカルにイメージがない場合は、Dockerがリポジトリからイメージを引っ張ってきます。
docker run -d -p 80:3000 arnab74/nodeexpress-alibaba-docker-tutorial:0.1ここでは、ホストに80番ポートを使用しました。そのため、簡易アプリケーションサーバの公開IP(サーバ管理画面で利用可能)を利用してサイトを閲覧する際には、ポート番号を使用する必要はありません。
http://public_ip にアクセスしてサイトをテストします。アプリケーションが起動しているのが確認できるはずです。
結論
これらは、Ubuntu Linux上でビジュアルコードを使用してNode.jsアプリケーションを開発し、アプリケーション用のDockerイメージを作成し、Dockerハブリポジトリを作成してDockerハブにイメージをプッシュし、最後にCentOSを使用してAlibaba CloudのSimple Application Server上にDockerハブイメージをデプロイするための基本的なステップです。
アリババクラウドは日本に2つのデータセンターを有し、世界で60を超えるアベラビリティーゾーンを有するアジア太平洋地域No.1(2019ガートナー)のクラウドインフラ事業者です。
アリババクラウドの詳細は、こちらからご覧ください。
アリババクラウドジャパン公式ページ
- 投稿日:2020-08-17T03:33:26+09:00
Azure Static Web AppsのAPI作成でLINE BOTを作る
前に書いた記事でAzure Static Web Appsを簡単に試してみましたが、後半の手順でAPIの作成も出来ました。
参考: たぶん10分で試せる。Azure Static Web AppsにWebサイトをデプロイして独自ドメイン設定とFunctionsでAPI公開まで
今回はこれを使ってLINE BOTを作ってみようと思います。
ちなみにStatic Web AppsのAPIの中身はAzure Functionsになる模様です。
参考: Azure Functions による Azure Static Web Apps プレビューでの API のサポート
環境
- macOS Catalina
- Node.js v12系
現状だとローカル実行やAzure FunctionsがNode.js v12までしか対応してなさそうでした。
APIエンドポイントを作ってみる(おさらい)
こんな手順です。
- まずは参考記事をもとに、Azure Static Web Appで静的サイトを作成してみる
apiフォルダ
を作成し、さらにlinebot
フォルダを作成linebot
フォルダ内にindex.js
とfunction.json
を作成index.jsmodule.exports = async function (context, req) { context.res = { body: { text: "Hello from the API" } }; };function.json{ "bindings": [ { "authLevel": "anonymous", "type": "httpTrigger", "direction": "in", "name": "req", "methods": [ "get" ], "route": "linebot" }, { "type": "http", "direction": "out", "name": "res" } ] }この状態でプッシュしてしばらくするとAPIが有効になります。
https://<APP ID>.azurestaticapps.net/api/linebot
にアクセスするとAPIが見えます。ローカル実行まで
まずはローカルで実行できる環境を整えます。
Azure Functionsの拡張機能のインストールと設定
VScodeにAzure Functionsの拡張機能をインストールします。
インストールが完了するとAzureマークがVSCodeのサイドバーに表示されます。選択するとサインインしましょう的なボタンがあるのでサインインします。
サインインすると少し読み込み待ち
Create New Project...
のボタンを選択し、Browse
を選択。作成した
apiフォルダ
を選択言語選択で
JavaScript
を選択テンプレート選択で
HTTP trigger
を選択関数名を
webhook
とし、承認レベルをanonymous
にします。こんな感じで
apiフォルダ
内にwebhookフォルダ
やその他ファイルが作成されます。Azure Functions拡張機能のタブに戻るとこのような表示になっています。
core toolsでローカル実行
Azure Functions Core Toolsというツールを使ってローカル実行をする模様です。
VScodeのコマンドパレットを開き(macだとcommand+shift+p)、
core tools
と入力しインストールします。バージョン選択ですが、レコメンドされてるので
Azure Functions v3
を選択します。しばらくするとインストールが完了します。
VSCodeのメニューの
Run > Start Debugging
を選択するとローカルサーバーが起動します。ちなみに、このときにNode.js v14を利用してたらエラーが出ました。執筆時点ではv12までの対応らしいのでv12に切り替えたらうまく行きました。
ターミナルではこんな感じで作成した
webhook
とlinebot
のエンドポイントが有効になったような表示になります。ブラウザでアクセスしてみるとちゃんと表示されました。
LINE BOTプログラムの作成
現状だとルートディレクトリに
apiフォルダ
とindex.html
がありますが、apiフォルダ
内にpackage.json
があるのでそこでnpm install
を実行していきます。
- ルートからapiフォルダへ
$ ls api index.html$ cd api$ ls host.json local.settings.json package.json webhook linebot package-lock.json proxies.json
- apiフォルダでモジュールのインストール
npm i @line/bot-sdk express azure-function-express通常だとAzure Functionsのお作法で書く必要がありますが、
azure-function-express
を利用することで、Azure Functionsっぽい書き方に依存せずに通常のexpressの利用っぽい雰囲気で書くことが出来ます。ひらりんさんの記事が参考になりました!
api/webhook/index.js
にコードを記述'use strict'; const line = require('@line/bot-sdk'); const createHandler = require("azure-function-express").createHandler; const express = require('express'); const config = { channelSecret: '作成したBOTのチャンネルシークレット', channelAccessToken: '作成したBOTのチャンネルアクセストークン' }; const app = express(); app.get('/api/webhook', (req, res) => res.send('Hello LINE BOT!(GET)')); //ブラウザ確認用(無くても問題ない) app.post('/api/webhook', line.middleware(config), (req, res) => { console.log(req.body.events); //ここのif分はdeveloper consoleの"接続確認"用なので削除して問題ないです。 if(req.body.events[0].replyToken === '00000000000000000000000000000000' && req.body.events[1].replyToken === 'ffffffffffffffffffffffffffffffff'){ res.send('Hello LINE BOT!(POST)'); console.log('疎通確認用'); return; } Promise .all(req.body.events.map(handleEvent)) .then((result) => res.json(result)); }); const client = new line.Client(config); async function handleEvent(event) { if (event.type !== 'message' || event.message.type !== 'text') { return Promise.resolve(null); } return client.replyMessage(event.replyToken, { type: 'text', text: event.message.text //実際に返信の言葉を入れる箇所 }); } module.exports = createHandler(app);大元はこちらの1時間でLINE BOTを作るハンズオンの記事のコードになっています。
参考記事をもとにLINE BOTのチャンネルシークレットとアクセストークンもコードに記載しておきます。
おうむ返し
ngrokでトンネリングして試してみましょう。
コードが出来たら先ほどと同様に
Run > Start Debugging
でローカルサーバーを起動させます。今回(デフォ?)7071ポートで起動したのでngrokで7071ポートにトンネリングさせます。
$ npx ngrok http 7071
これは別のターミナルで実行しておいた方が良いと思います。
こんな感じで
https://35027c542caa.ngrok.io
というURLが発行されました。このURLを使ってLINE DevelopersでWebhook URLの設定を行います。
今回はエンドポイントが
/api/webhook
になっているので、この場合はhttps://35027c542caa.ngrok.io/api/webhook
となります。この状態(ローカルサーバー起動中 + ngrok起動中 + Webhook URL登録済)でLINE BOTに話しかけると無事におうむ返しをしてくれました。
ひとまずローカルで実行できて一安心。。
デプロイして永続化する
デプロイは簡単で、もともとGitHub連携ありきでAzure Static Web Appsを作っているのでローカルで作ったものをプッシュすればOKです。
裏側でGitHub Actionsでビルドされる模様なので少し待ちましょう。
しばらくするとポータルの画面にもwebhook関数が表示されます。
https://<APP ID>.azurestaticapps.net/api/webhook
にブラウザでアクセスするとHello LINE BOT!
の表示が見えるようになると思います。最終的にこのアドレスをLINE BOTの管理画面からWebhook URLに登録します。
これでデプロイも完了し永続化まで出来ました。
念のため最後におうむ返しがちゃんと動くか確認しましょう。
おまけ 環境変数の利用
ソースコードの
チャンネルシークレット
とチャンネルアクセストークン
をコードに直書きしてましたが環境変数置き換えも出来ます。//省略 const config = { channelSecret: process.env.CHANNEL_SECRET, channelAccessToken: process.env.CHANNEL_ACCESS_TOKEN, }; //省略ポータルの構成の箇所から環境変数の追加ができます。
パスワードやトークンはここを活用すると良さそうです。
最後にチェックをして保存を押すことで保存されるのですが、これを忘れると値が保存されないので注意です。
まとめと所感
Static Web AppsでLINE BOTを作成することが出来ました。
当たり前ですがMSエコシステムということでVSCodeを使わないと厳しいかもしれないですね。
この辺は趣味趣向ありそうです。内部はAzure Functionsを使ってるっぽいですが、Azure Functionsのリソースは一個も作っていないので金額とかは特に発生せずに使えてるのかな......
Static Web Appsの管理画面がシンプルすぎて稼働状況もいまいちわからないですが、とりあえずしばらく稼働させてみます。