GitHub から Web アプリをデプロイする:Python、Node、Go、Java、静的サイト

プログラムを書くことと、それをほかの人が開ける場所で動かすことは別物で、後者は普段の授業ではまず扱えない部分です。ここでは生徒が公開 GitHub リポジトリから、クラウドアカウントもカードもなしにデプロイでき、教員は課題の提出物としてデプロイしたアプリを求めることができます。

Python、Node、Go、Java、HTML・CSS・JavaScript の静的サイトをデプロイできます。これは学習とデモのためのもので、本番環境のホスティングではありません。教員に見せる、数人と共有する、リンクを提出するには十分な長さですが、サービスを運用できるほどの長さには意図的にしていません。

サンプルから始める

「デプロイ」ページにはサンプルアプリ「File uploads」があります。Node、Python、Go、Java で同じアプリが用意されていて、言語を比べられます。ファイルをアップロードすると S3 に保存され、その保存先が Postgres に記録されます。「このサンプルをデプロイ」を押すと、必要なもの(データベースとクラウドスタック)がすべて自動で作られ、アプリは両方に接続済みの状態で立ち上がります。事前の準備も、接続文字列のコピーも必要ありません。「フォームに入力」は、立ち上げる前にリポジトリやブランチを変えたい場合のためのものです。

ログインする前から表示されているので、メールアドレスを登録する価値があるかを検討している人も、まず実際に動いているアプリを見られます。ボタンを押すまで誰のためにも何も作られないので、誰のアプリ利用時間も消費しません。すでにデータベースやクラウドスタックを持っている生徒には、2つ目を作らずにそれが使われます。

コードは公開されていて、読む価値があります。短く、README では生徒が最初につまずきやすい3つの点を説明しています。S3 をホスト名ではなくパスで指定すること、クラウドスタックは空の状態で始まるので自分でバケットを作ること、そしてデータベースに行を書く前にファイルを S3 に書くことです。こうすれば、失敗しても開けないファイルがページに残ることはありません。

表示したくない場合は、その行の「非表示にする」を押せば、以後は表示されません。

アカウントなしで試す

アプリが動くところを見るのにアカウントは要りません。「デプロイ」を押すか、「データベース」タブや「クラウド」タブで「作成」を押すと、そのブラウザーに一時的なアカウントが作られ、ログインした状態になります。ゲストには専用の上限があり、システム管理者が変更できます。アカウントは最後に使ってから24時間保持され、デプロイ1回あたり最長30分動作し、デプロイは合計2回、データベースは1つまでです。これとは別に、データベースの数に含まれないクラウドスタックを1つ持てます。

ゲストはアプリを見られる人を招待できません。招待は名前のある人が送るリンクだからです。非公開のリポジトリもデプロイできません。誰も戻れないアカウントに保存したトークンは、取り消しようがないからです。「このアカウントを残す」でメールアドレスとコードを入力すると、同じアカウントが自分のものになり、デプロイしたものもすべて引き継がれます。誰も戻ってこないゲストは、そのアプリ、データベース、ファイル、保存済みのコンテナーラボとともに削除されます。

生徒が入力するもの

GitHub のリポジトリとブランチ、言語、ビルドコマンド、起動コマンドです。入力欄にはあらかじめデプロイできるものが入っています。生徒自身が最後に使ったリポジトリ、まだ一度もデプロイしたことがなければ、選んだ言語用の当社のもの(hello-flask、hello-node、hello-go、hello-spring、hello-static)です。そのため1回目は必ず動き、2回目からが生徒自身の作品になります。言語を変えると例が別の例に入れ替わりますが、生徒が入力した内容が上書きされることはありません。

非公開のリポジトリも使えます。リポジトリ欄の下にある「このリポジトリは非公開です」にチェックを入れ、GitHub トークンを貼り付けます。そのリポジトリだけに限定し、読み取り専用で、有効期限を設定した fine-grained personal access token を使ってください。トークンは暗号化して保存され、誰にも二度と表示されず、コードの取得にだけ使われます。動作中のアプリには渡らないので、生徒がデプロイしたものがそれを読むことはできず、採点する人もトークンを見ることなくアプリをビルドできます。チェックを外せばトークンは取り消されます。

アプリが環境から読み取る設定は、同じフォームに名前と値の行として入力します。最大20行、値は1行あたり最大4 KB です。PORT と実行環境自身の名前は使えません。設定は暗号化して保存され、保存後は誰にも表示されません。ページには黒丸が表示され、「置き換え」と「削除」が使えます。提出物は保存済みのデプロイを指すので、採点する人は生徒の変数でアプリをデプロイし、見られるのは変数名だけです。フォームで選んだデータベースと一緒に DATABASE_URL を入力すると拒否され、どちらを外すかを示す文が表示されます。

アプリは割り当てられたポートで待ち受ける必要があります。これがこの演習で本当に学ぶべきただ1つのことで、どのホスティングサービスでも、つまずいて初めて身につくことです。

同じフォームにある2つのチェックで、使えるものが増えます。自分専用のデータベースと、オブジェクトストア、NoSQL テーブル、メッセージキューを備えたクラウドスタックです。どちらもアプリと一緒に起動して自分の環境変数を設定するので、ページを表示するだけのアプリではなく、アップロードされたものを保存するアプリを課題として求めることができます。

デプロイフォーム:GitHub リポジトリ、ブランチ、言語、ビルドコマンド、起動コマンド
リポジトリ、ビルドコマンド、起動コマンド。入力欄の例はそのままデプロイできます。

対応している言語

Python、Node、Go、Java、HTML・CSS・JavaScript の静的サイトに対応しており、それ以外には対応していません。それぞれがその言語用のコンテナーでビルド・実行され、その言語のパッケージレジストリにだけ接続できます。Python は gunicorn で動作するので Flask も Django も使えます。Node は start スクリプトが実行するものがそのまま動きます。Go と Java はソースからビルドされ、Java は Spring Boot アプリケーションとしてビルドされます。静的サイトはリポジトリにあるとおりにそのまま配信されます。

言語ごとに、当社の動作するサンプルリポジトリがフォームに入っているので、何もデプロイしたことのない生徒にも出発点があります。

静的サイトは最も制限の多い種類です。何もインストールしないので、ビルドが接続できるのは GitHub だけです。ビルドコマンドはリポジトリの最上位に index.html があるかを確認します。docs/ や dist/ にページを置いたままだとエラーなくデプロイされ、ファイルの一覧が表示されてしまうためです。サブフォルダーを配信するには、ページを移動するのではなく、起動コマンドに --directory とそのフォルダー名を追加します。

どこで動き、誰が見られるか

すべてのアプリには learntools.dev の下に専用のアドレスが付きます。2つの単語と数字の組み合わせか、生徒が選んで持ち続ける名前です。名前を選べば、履歴書に載せたリンクも次にデプロイしたときにそのまま使えます。選んだアドレスは削除するまで生徒のもので、保持されているアドレスをほかの人が取ることはできません。

アドレスを推測してアプリにアクセスすることはできません。生徒は最大5人までメールで招待できます。招待された人はリンクを開き、同じアドレスに届いたコードを入力するので、招待を転送して使うことはできません。生徒自身は自分のページからアプリを開けます。

教職員はアプリを停止できます。システム管理者はどのアプリ、データベース、クラウドスタックでも停止でき、学校の教職員なら誰でも、学校管理者に限らず、その学校の生徒のものを停止できます。報告を受けるのは授業を担当している人だからです。以前はアプリを止めるものはアプリ自身の時間制限しかなく、今すぐ止めなければならない場面ではまったく役に立ちませんでした。

停止はあくまで停止です。保存されたデータもアドレスも残り、生徒は再び起動できます。ほかの人の作業を取り上げることはそれとは別のことで、誰にもできません。所有者以外による停止はすべて記録され、生徒が教職員と同じ記録を読める「デプロイ」ページと、学校自身の管理ログに残ります。

動作時間

アプリは1時間の動作が保証され、空きがあれば最大4時間まで動き続けます。誰も見ていない状態が30分続くと停止し、アプリの利用時間は各アカウント1日8時間までです。

これは学習とデモのためのもので、本番環境のホスティングではありません。教員に見せる、数人と共有する、リンクを提出するには十分な長さですが、サービスを運用できるほどの長さには意図的にしていません。

デプロイする前にその日の残り時間が表示され、動作中はアプリが最後に出力した数行が表示されます。ログは停止後3日間保存されます。ログを最も読みたくなるのは、まさに停止した後だからです。

保証された時間を過ぎても、アプリはほかに誰もその場所を必要としない間は動き続けます。誰かが必要としたときに最初に停止されるのもそのアプリです。満杯のマシンに新しいデプロイが来ると、最も長く動いているアプリが停止され、対象は保証時間をすでに過ぎたものだけです。5つ目の数値は分ではなくビルドの回数を数えるもので、初期値は1日20回です。ビルドは、アプリがその後どれだけ動くかに関わらず同じ負荷がかかり、コミットのたびに再デプロイする生徒がいるとクラスが順番待ちになるためです。システム管理者は、これらすべてをプラットフォーム全体と学校ごとに設定します。

一度に動かせるアプリは1つです。今のアプリが停止するまで「デプロイ」ボタンは押せず、ページには、順番待ち(前に何人いるかも表示)、ビルド中、起動中、停止中のどれかが表示されます。自然に停止したアプリは、ビルドできなかったアプリとは区別して、そのアプリ自身の最後の出力とともに報告されるので、プログラムの不具合でビルドログを延々と探すことはありません。アプリが出力した最後の10行は約1分ごとに更新され、ログ全体はダウンロードでき、過去のデプロイは、いつ、どの言語で、どのリポジトリから、どう終わったか、そのログという表になります。

アプリと一緒に使うデータベース

「デプロイ」の下の「アプリ」の横にある「データベース」タブでは、生徒が自分専用のデータベースを3つまで作れます。それぞれ最大10 MB で、サーバーとして動く PostgreSQL か MySQL、またはファイルとしての SQLite です。デプロイフォームでどれかを選ぶと、アプリと一緒にサーバーが起動して DATABASE_URL がそこを指すように設定されるので、ノートパソコンで SQLite 向けに書いたコードも、ここで同じ変数を読みます。SQLite のファイルはアプリの中に置かれ、アプリの停止時に保存されます。

名前を尋ねられることはありません。データベースには、生徒のアプリが応答するアドレスの名前に、2種類のどちらかを示す語が付いた名前が付きます。sams-shop.learntools.dev のアプリなら、データベースは sams_shop_db、クラウドスタックは sams-shop-cloud になります。データベース名は SQL の名前なので、アドレスのハイフンはアンダースコアに変わります。どのエンジンでもどのドライバーでもそのまま受け付けられる形だからです。クラウドスタックはハイフンのままです。名前がストレージのバケット名になり、バケット名にはアンダースコアを使えないためです。同じアドレスから2つ目のデータベースを作ると sams_shop_db_2 のように番号が増え、数字で始まるアドレスでは語が先に付いて db_2048_game となり、まだ何もデプロイしていない人には db_1 や cloud-1 が付きます。ボタンを押す前に、何を作るかがフォームに表示されます。

サーバーはアプリとまったく同じ時間だけ動作し、データは停止時に保存されて起動時に戻されます。接続できるのはここでデプロイしたアプリだけです。ページには接続情報が表示されるので、生徒は変数の意味を読み取れます。提出されたアプリを採点する人は、生徒のデータが入った生徒のデータベースも一緒に受け取り、保存された内容を変更することはできません。

各データベースには「起動」「停止」「ダウンロード」「削除」があります。サーバーは単独で起動でき、保存されたデータは .sql ダンプとして、SQLite なら .sqlite ファイルとしてダウンロードできます。SQLite のファイルは、アプリから /data の中にデータベース名で見つかり(たとえば /data/sams_shop_db.sqlite)、そのパスは DATABASE_PATH に設定されます。動作中のサーバーには「クエリ」ボタンがあり、SQL プレイグラウンドと同じクエリとスキーマのタブが、実際のデータベースに対して生徒自身のロールで開きます。ここではスキーマタブは読み取り専用です。実行中のデータベースや、提出済みのデプロイが指しているデータベースは削除できません。提出していないデプロイはデータベースを失い、それなしでデプロイされます。上限の10 MB に達するとサーバーは読み取り専用になり、最後の変更が保存されなかったことがページに表示されます。認証情報は自動で生成され、選ぶことはできず、パスワードは封印して保存されます。ページには URL、ホスト、データベース、ユーザーが表示され、パスワードは求めたときに表示されます。

1つのセッション:アプリ、データベース、クラウドスタック、ターミナル

「デプロイ」はバーの1つの項目で、「アプリ」「データベース」「クラウド」のタブがあり、どのタブも上部に同じ生徒のセッションの図を表示します。アプリ、データベース、クラウドスタック、ターミナルが入った1つのプライベートネットワークで、各スロットに入っているものが示されます。動いているものはすべて、app、db、cloud という固定の名前でほかのものに接続するので、チュートリアルの設定がそのまま使え、URL は要りません。

どのタブでも「ターミナルを開く」を押すと、セッションの横でシェルが起動し、psql、mariadb、aws、curl がそのセッションのデータベース、クラウドスタック、アプリを指した状態で使えます。ターミナルはセッションごとに1つで、データベースの時間として数えられます。ホームフォルダーはセッションとともに残るので、残るのは生徒がデータベースやバケットに入れたものです。

課題として:デプロイしたアプリを提出する

記述式の課題で、ファイルの代わりにデプロイしたアプリを求めることができます。課題文はいつもどおりあなたが書き、変わるのは提出物です。

  1. 課題を設定する. 「提出物」で「デプロイしたアプリ」を選び、続いて生徒がデプロイに使う言語を選びます。
  2. 生徒がデプロイする. 生徒の課題ページに「アプリをデプロイ」が表示され、押すとその言語が選択された状態でデプロイページが開きます。生徒はデプロイして動作を確認し、「提出」を押します。
  3. 提出されるもの. デプロイ全体です。その名前と、その中のすべてのアプリが、リポジトリ、ブランチ、そのアプリが実行した2つのコマンドとともに提出されます。フロントエンドと API を持つ生徒は、2つではなく1つの作業として提出します。ほかの提出物と同じく課題に対して保存され、採点、差し戻し、バージョン管理も同じように行われます。
  4. 実行して採点する. 生徒の提出物を開いて「アプリをデプロイ」を押します。同じアプリが専用のアドレスで再び立ち上がり、クラス全員の提出物を立ち上げても、あなた自身の1日のアプリ利用時間は消費しません。デプロイに複数のアプリが含まれる場合は、それぞれが専用のリンク付きで一覧表示され、1つずつ立ち上がります。

デプロイの採点と、コンテストのための上限

提出物は、動いているデプロイである必要はありません。ビルドが通らない生徒も、そのことをコメントのやり取りで伝えたうえで提出できます。拒否されるのは、デプロイページ自身が拒否するリポジトリやブランチだけで、提出されたものは少なくともビルドできるものになります。

採点する人には1日のアプリ利用時間の上限がなく、それは採点中の作業に限られます。25件の提出物を立ち上げれば、生徒自身の枠は最初の数件で尽きてしまうため、1日の分数と、一度に1つだけという規則は適用されず、ページにもそう表示されます。セッションの上限は適用されるので、置き忘れたアプリはいずれ終了します。自分のアイデアをデプロイする教員は、ほかの人と同じ通常の上限が適用されます。

課題には独自の上限を設定でき、コンテストや試験はそのためのものです。課題の設定タブでは、許可するデプロイの回数と、各アプリの動作時間を指定します。これらは課題自身の時計の中で数えられるので、始めるのが遅い人にもその人自身の枠があり、時計が動いている間に生徒がデプロイするすべてのアプリに適用されます。その課題用だと申告したアプリだけではありません。課題が変えられるのは、学校が許可している範囲を短くする方向だけです。

よくある質問

どの言語をデプロイできますか?
Python、Node、Go、Java、HTML・CSS・JavaScript の静的サイトです。ビルドコマンドと起動コマンドはその言語の範囲内で生徒が編集でき、それ以外の言語のリポジトリはビルドされません。
これはホスティングサービスですか?
いいえ。これは学習とデモのためのもので、本番環境のホスティングではありません。教員に見せる、数人と共有する、リンクを提出するには十分な長さですが、サービスを運用できるほどの長さには意図的にしていません。アプリは自動的に停止し、生徒は必要になればいつでも再デプロイできます。アドレスを選んでいれば、同じアドレスで再デプロイされます。
アプリにデータベースを持たせられますか?
はい。アプリの横で動くサーバーとしての PostgreSQL か MySQL、またはアプリの中に置かれるファイルとしての SQLite を使えます。それぞれ最大10 MB、生徒1人あたり3つまでで、「データベース」タブで作成し、デプロイフォームで選ぶと DATABASE_URL が設定されます。サーバーはアプリと同じ時間だけ動作し、実行と実行の間もデータを保持します。接続できるのはここでデプロイしたアプリだけで、ノートパソコンからは接続できません。
アカウントなしで試せますか?
はい。「デプロイ」を押すと、そのブラウザーに一時的なゲストアカウントが作られます。ゲストには専用の上限があり、「このアカウントを残す」でメールアドレスとコードを入力すると、デプロイしたものをそのまま引き継いで、正式なアカウントになります。
アプリに API キーのような秘密の値を持たせられますか?
はい。デプロイフォームには、名前と値の行を最大20行まで入力できます。暗号化して保存され、保存後は二度と表示されません。実行中のアプリには環境変数として渡され、採点する教員に見えるのは変数名だけです。
生徒に GitHub アカウントは必要ですか?
指定するリポジトリが必要で、それ自体が教える価値のあることです。バージョン管理とデプロイはひとつながりの学びだからです。リポジトリは公開でも非公開でもかまいません。非公開のものは読み取り専用の GitHub トークンを貼り付けてデプロイします。トークンは暗号化して保存され、誰にも表示されません。
生徒はアドレスを選べますか?
はい。「アプリを作成」で選べます。ここで作業に名前を付け、アプリが応答するアドレスを選びます。小文字、数字、ハイフンからなる自分で決めた名前で、ほかの誰も保持しておらず、予約語でもないものです。その下のデプロイフォームではどちらも尋ねないので、決めるのは一度だけです。フォームの下にある保存済みデプロイの表から削除するまで生徒のもので、削除すればほかの人がそのアドレスを使えるようになります。
フォームに入力し直さずに、同じアプリをもう一度立ち上げられますか?
はい。フォームの下にある保存済みデプロイの表の各行に「再デプロイ」があり、まったく同じリポジトリ、ブランチ、コマンド、変数を、同じアドレスに1回の操作で立ち上げ直せます。先に何かを変更したい場合のために「使う」も残っています。「停止」で元に戻せるので、実行前に確認は求めません。事前に伝えるのは1点だけで、専用のアドレスを持たないデプロイは新しいアドレスで立ち上がるため、古いリンクは使えなくなるということです。課題として提出したデプロイはこの方法で立ち上げ直すことはできますが、それ以外の方法では変更できません。ここでの「読み取り専用」とは、まさにそういう意味です。
学校がこの機能をオフにできますか?
オフにはできませんが、制限はできます。システム管理者は、プラットフォーム全体と学校ごとに5つの数値を設定します。アプリに保証される時間、最長の動作時間、誰も見ていないときに動き続ける時間、1日の合計時間、1日のデプロイ回数で、それぞれ数分、または1回まで下げられます。
停止するとどうなりますか?
アプリはなくなり、ログは3日間残ります。選んだアドレスは保持されるので、再デプロイすれば同じリンクでアプリが戻ります。ランダムに付いたアドレスは保持されません。
教員が生徒のアプリを停止できますか?
はい。その学校の教職員なら誰でも自分の学校の生徒のアプリを停止でき、システム管理者は誰のものでも停止できます。そのため、生徒がオンラインに公開したものについて苦情があれば、その日のうちに対応できる人がいます。停止はアプリを止めるだけで何も削除しません。データもアドレスも残り、生徒は再び起動できます。生徒には、誰がいつ停止したかが、デプロイに使うのと同じページに表示されます。