LoginSignup
6
6

More than 3 years have passed since last update.

Deno in Dockerなアプリ開発

Last updated at Posted at 2020-07-15

はじめに

練習がてら、タイトルの技術を使用した簡単なアプリを作ってみました。
ソースコードはこちら(UI)こちら(サーバ)です。

アプリそのものというより、構築方法に主眼を置いた記事です。
以下が本稿で説明する内容です。

  • DenoコンテナをVS Code Remote Containersで開発するための環境構築方法
  • DenoコンテナをGitHubからAzureに自動デプロイする方法

アプリの概要

Qiitaで良い記事を見つけると、ストックをしますが見返すことがほぼありません。これではストックの意味がないので、過去にストックした記事をランダムで表示させることで、過去に覚えた(はず)の知識のおさらいをするアプリです。

作成したアプリはこちらです。ユーザ名欄に任意のユーザ(ユーザ自身を想定)を入力し、表示ボタンを何回か押してみてください。

構築の練習が目的のため、アプリ自体はかなりしょぼいのでご了承ください。
またAzure Web Appsの無料枠を使っているため初回アクセス時は重いです。

主な使用技術

  • Azure App Service ・・・ サーバアプリのデプロイ先
  • Azure DevOps ・・・ サーバアプリの自動デプロイ
  • Deno ・・・ サーバアプリ作成に使用
  • VS Code Remote Containers(Docker) ・・・ 開発環境として使用
  • GitHub Pages ・・・ 画面のデプロイ先1
  • React ・・・ 画面作成に使用1

構成

UIとサーバのリポジトリを分けており、UIはGitHub Pages、サーバはコンテナ化してAzure DevOpsのPipelinesで自動デプロイするようにしています。

また、開発環境は二つともVS Code Remote Containersで開発するようにしています。

image.png

DenoコンテナをVS Code Remote Containersで開発するための環境構築方法

重要な部分だけかいつまんで説明します。コードの全体はこちらにあります。

VS Code Remote Containersの設定をする

devcontainer.jsonを以下のように設定します。拡張機能のdenoland.vscode-denoをインストールし、"deno.enable": trueとするところがポイントです。

.devcontainer/devcontainer.json
{
  "name": "Your-Memory-Server",
  "dockerFile": "Dockerfile",
  "shutdownAction": "none",
  "appPort": "5000:5000",
  "extensions": [
    "denoland.vscode-deno",
    "eamodio.gitlens",
    "mhutchie.git-graph"
  ],
  "settings": {
    "terminal.integrated.shell.linux": "/bin/bash",
    "editor.formatOnSave": true,
    "editor.tabSize": 2,
    "editor.detectIndentation": false,
    "editor.insertSpaces": true,
    "deno.enable": true
  }
}

Dockerfileは以下のようにしました。denoのインストールは公式の通りですが、私の環境ではパスを設定しないとdenoコマンドが動きませんでした。また、開発用にgitやcurlがほしかったためベースイメージをbuildpack-depsとしています。

.devcontainer/Dockerfile
FROM buildpack-deps:stretch

RUN curl -fsSL https://deno.land/x/install/install.sh | sh
ENV DENO_INSTALL /root/.deno
ENV PATH $DENO_INSTALL/bin:$PATH

この状態でVS CodeのRemote-Containers: Reopen in Containerをクリックすることでコンテナ内に入り、開発が可能です。
image.png

VS Codeでdenoアプリをデバッグする

launch.jsonを以下のように設定し、F5でデバッグ可能です。

.vscode/launch.json
{
  "version": "0.2.0",
  "configurations": [
    {
      "type": "node",
      "request": "launch",
      "name": "Launch Program",
      "runtimeExecutable": "deno",
      "runtimeArgs": [
        "run",
        "--inspect-brk",
        "--allow-net",
        "--allow-read",
        "-A",
        "index.ts"
      ],
      "port": 9229
    }
  ]
}

--allow-netはサーバ起動、--allow-read.env読み込みのために指定しています。

本番ビルド用のDockerfileを作成する

上記のDockerfileはあくまで開発用のコンテナを作成するためのものなので、実際にAzureにデプロイするコンテナを作成するDockerfileも別で用意します。

Dockerfile
FROM buildpack-deps:stretch-curl

ENV DIRPATH /opt/app
WORKDIR $DIRPATH

RUN apt-get update && apt-get install -y --no-install-recommends \
    unzip

RUN curl -fsSL https://deno.land/x/install/install.sh | sh
ENV DENO_INSTALL /root/.deno
ENV PATH $DENO_INSTALL/bin:$PATH

COPY . $DIRPATH

ENTRYPOINT deno run --allow-net --allow-read --allow-env index.ts

本番環境では.envを介さずに直接環境変数を読み込むため、--allow-envを追加しています。

コード

リクエストパラメータとしてユーザ名を投げるとそのユーザがストックした記事一覧をレスポンスとして返す簡単なサーバです。deno標準のhttpライブラリを使用していますが、どうやらルーティングやリクエストパラメータのパース機能が用意されていないようなので、しょうがなく自前実装しています。

本格的にやるなら以下のようなライブラリを使った方がよさそうです。

また、ストック記事は100件しか取得していませんしキャッシュもしていません。これは、単に実装の手を抜いたためです。

index.ts
import { serve } from "https://deno.land/std/http/server.ts";
import { config } from "https://deno.land/x/dotenv/mod.ts";

let env = config();
if (Deno.env.get("API_KEY")) {
  env.API_KEY = Deno.env.get("API_KEY")!;
}

for await (const req of serve({ port: 5000 })) {
  if (req.method === "GET" && req.url.split("?")[0] === "/api/v1/article") {
    let params: { [key: string]: any } = {};
    const paramAry = req.url.split("?")[1].split("&");
    for (const param of paramAry) {
      const [key, value] = param.split("=");
      params[key] = value;
    }
    const res = await fetch(
      `https://qiita.com/api/v2/users/${params.username}/stocks?per_page=100`,
      {
        headers: {
          Authorization: `Bearer ${env.API_KEY}`,
        },
      },
    );
    const json = res.json();
    const data = await json;
    req.respond({
      status: 200,
      headers: new Headers({
        "Content-Type": "application/json",
      }),
      body: JSON.stringify(data),
    });
  } else {
    req.respond({
      status: 404,
      body: JSON.stringify({}),
    });
  }
}

DenoコンテナをGitHubからAzureに自動デプロイする方法

デプロイ先のAzure Web Appsを作成する

はじめに、Azureポータルでデプロイ先のコンテナを作成します。
image.png

ここの詳細な手順は省略します。

自動デプロイ設定をする

  1. 作成したAzure Web Appsで、デプロイセンターを選択し、Get startedをクリックします。
    image.png

  2. 最初にデプロイ元を選択します。ここではGitHubを選択し、Nextをクリックします。
    image.png

  3. 次にGitHubの中から対象のリポジトリを選択します。Authorizeをクリックし、GitHubにログインします。
    image.png

  4. 対象のリポジトリとブランチを選択し、Nextをクリックします。
    image.png

  5. 次に、対象のリポジトリからビルド用のDockerfileと公開ポートを選択します。
    今回は開発用と本番用で二種類のDockerfileがあるため、本番用を選択するように気をつけます。Portにはコンテナ内のアプリのポートを指定します(仮に5000とすると、docker run -p 80:5000になるイメージ)。
    image.png

  6. Azure DevOpsのプロジェクト名などを入力し、最後にDoneをクリックします。
    image.png

完了すると、Azure DevOpsにデプロイ用のパイプラインが作成されます。これにより、指定したGitHubリポジトリのmasterブランチからビルドされたDockerイメージがAzure Container RegistryにPushされ、Azure App Serviceにアプリがデプロイされます。

おわりに

AzureはUIが綺麗で好きです。次はこの構成でちゃんとしたアプリを作成したいですね。

ちなみに、この構成を作るにあたって結構はまりました。
結果的には大した事のない問題だったのですが、一応記事にしてあります。
↓↓↓↓
Azure App Serviceに環境変数が設定されなくて困った。と思ったら原因が違った話


  1. 本稿では触れません。 

6
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
6