はじめに
この記事は、TIS Advent Calendar 2018の10日目の記事です。
書かれていること
このエントリでは、Stack OverflowクローンであるScooldの簡単な紹介と、少し中身の話を書いています。
QAサイト?
日々の業務で、技術的な困りごとだったり、相談ごとだったりをする時には、どうしているでしょうか?
様々なアプローチがあると思いますが、知識の蓄積や誰でも内容が見られて親近感が出そうなものとして、QAサイトというものもあると思います。
そんなわけで、社内にStack OverflowクローンであるScooldを導入して、技術的な質問を投稿したり、質問に答えたりするような活動をしています。
あくまで社内に閉じたものだったりはしますが、社内で他の人に助けを求めることができたり、もっとオープンな環境に向けてだと心理的なハードルの高さもあったりするので、こういう解法もそう悪くはないのでは?と思ったりします。
Scoold
Scooldは、Erudika社がオープンソースで提供しているQ&Aプラットフォームです。
Scoold is an open source Q&A platform written in Java.
Stack Overflowにインスパイアされていることが書かれています。
Scoold is inspired by StackOverflow and implements most of its features.
ライセンスは、Apache License Version 2.0です。
商用版もあったりします。
OSS版の機能の一覧。
- データベースが選択可能で、クラウドへのデプロイにも最適化している
- 全文検索
- 分散オブジェクトキャッシュ
- Locationの情報を使って、「自分に近い位置」の投稿をフィルタリングできる
- 多言語サポート
- 評価と投票によるバッヂシステム
- スペース(チーム) … 質問やユーザーをグループで分割できる
- jQueryベースの最小限のフロントエンド
- Materialize CSSによるモダンでレスポンシブなデザイン
- よく似た質問に対するサジェストをして、重複した質問する前にヒントを出す
- 回答やコメントがあった時のメール通知
- Spring BootによるUber JAR
- LDAP認証のサポート
- ソーシャルログイン(Facebook, Google, GitHub, LinkedIn, Microsoft, Twitter)とGravatarのサポート
- コードのシンタックスハイライト、GitHub Flavored Markdownのサポート
- 絵文字のサポート
- SEOフレンドリー
商用版になると、このあたりが増えるようです。
- 好きな投稿をSticky(固定)にする
- SAMLサポート
- 匿名ユーザーの投稿
- 無制限のスペース
- 複数の管理者を設定可能
- 複数のドメインをサポート
- より高度なハイライト
- 画像アップロード
- セキュリティ通知
Qiita上でもScooldを活用したという記事もあり、自前でチーム内だったり組織内にQAサイトを構築するのには良いのかもしれません。
またScooldではありませんが、他の手段としてはStack Overflow for Teamsを検討するのもありでしょう。
チーム専用のプライベートなQ&Aサイトが作れる「Stack Overflow for Teams」提供開始。月額10ドルから
まあ、今回はScooldがテーマなので、こちらを掘り下げていきます。
Scooldは単体では動作せず、ParaというAPIサーバーをバックエンドに持ちます。
Scooldと同じく、ライセンスはApache License Version 2.0です。
Scooldは、ParaのREST APIを使用して、アクセスを行います。
Paraは、汎用のAPIサーバーアプリケーションです。Scooldとの役割分担を簡単に言うと、ScooldはUI担当、Paraはデータ操作担当です。
A general-purpose backend framework for the cloud
汎用といっても、相応の目的に特化したものではあるのですが。
インストールしてみる
では、ScooldをインストールしてローカルにQAサイトを立ち上げてみましょう。
ちなみに、単純にScooldを評価したいだけの場合は、デモサイトがあるのでそちらで試してみるのが良いと思います。
前述の通り、ScooldはバックエンドにParaを必要とします。
Paraはparaio.comでサービスとして提供されているものもあるのですが、今回はParaもローカルで起動してみる方針としましょう。
実行環境
OSはUbuntu Linux 18.04 LTSです。
$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description: Ubuntu 18.04.1 LTS
Release: 18.04
Codename: bionic
また、ScooldとParaのソースコードより、Java 8を対象とした方が良さそうなので、Javaは8を選択します。
https://github.com/Erudika/scoold/blob/1.31.0/pom.xml#L9-L13
https://github.com/Erudika/para/blob/v1.31.0/pom.xml#L145-L146
$ java -version
openjdk version "1.8.0_191"
OpenJDK Runtime Environment (build 1.8.0_191-8u191-b12-0ubuntu0.18.04.1-b12)
OpenJDK 64-Bit Server VM (build 25.191-b12, mixed mode)
また、コマンドラインツールを使う際には、Node.jsが必要です。
Paraのインストール
Paranのインストールは、GitHubのQuickStartに沿って見ていけばOKです。
Paraに関してはドキュメントも充実しているので、こちらを見て進めていってもよいでしょう。
Paraのダウンロード。
$ wget https://oss.sonatype.org/service/local/repositories/releases/content/com/erudika/para-jar/1.31.0/para-jar-1.31.0.jar
なお、Paraは実行可能WARも作成されており、WARを使った起動もできるようになっています。
ドキュメントに沿って、設定ファイルを作成します。
application.conf
# the name of the root app
para.app_name = "Para"
# or set it to 'production'
para.env = "embedded"
# if true, users can be created without verifying their emails
para.security.allow_unverified_emails = false
# if hosting multiple apps on Para, set this to false
para.clients_can_access_root_app = true
# if false caching is disabled
para.cache_enabled = true
# root app secret, used for token generation, should be a random string
para.app_secret_key = "b8db69a24a43f2ce134909f164a45263"
# enable API request signature verification
para.security.api_security = true
# the node number from 1 to 1024, used for distributed ID generation
para.worker_id = 1
ちなみに、設定ファイルはTypesafe Configを使って読み込みます。
起動。
$ java -jar -Dconfig.file=./application.conf para-jar-1.31.0.jar
起動時に、ログにこんな内容が出力されます。
2018-12-09 18:25:48 [WARN ] Server is unhealthy - root app not found. Open /v1/_setup in the browser to initialize Para.
/v1/_setup
にアクセスしてね、と言っているので、curl
やブラウザなどでアクセスしてみます。
$ curl localhost:8080/v1/_setup
{
"accessKey" : "app:para",
"message" : "Save the secret key - it is shown only once!",
"secretKey" : "3rB4SvKiTsMaSd2g7qXvGdPtezFmkROhWwCgyxV48OMtSKlVXklpMQ=="
}
すると、secretKey
が得られます。この値を覚えておきましょう。
Scooldのインストール
続いて、Scooldをインストールします。こちらも、Quick Startを見ながら。
まず最初に、Paraにpara-cli
で新しいアプリケーションを作成します。この過程で、先ほどのParaをセットアップした際の情報を使用します。
$ npm install -g para-cli
$ para-cli setup
Secret key not provided. Make sure you call 'signIn()' first.
Para Access Key: app:para
Para Secret Key: 3rB4SvKiTsMaSd2g7qXvGdPtezFmkROhWwCgyxV48OMtSKlVXklpMQ==
Para Endpoint: http://localhost:8080
✔ New JWT generated and saved in /$HOME/.config/para-cli-nodejs/config.json
✔ Connected to Para server v1.31.0 on http://localhost:8080. Authenticated as: app Para (app:para)
「新しいアプリケーション」ってなんだ?という話ですが、Paraは汎用のバックエンドサーバーという位置づけであり、ScooldはParaを使うアプリケーションの一種だということですね。
なので、今回は「Paraを使うScooldというアプリケーションを作りました」ということになります。
確認。
$ para-cli ping
✔ Connected to Para server v1.31.0 on http://localhost:8080. Authenticated as: app Para (app:para)
新しいアプリケーションの作成。
$ para-cli new-app "scoold" --name "Scoold"
✔ App created:
{
"accessKey": "app:scoold",
"message": "Save the secret key - it is shown only once!",
"secretKey": "JZODlJVH1F5pb6vKA6qae8XQYP7MaGOgrXnK3RN6nMZoemSMVmbnag=="
}
この情報も、やはり重要なので覚えておきましょう。
Scooldのダウンロード。
$ wget https://github.com/Erudika/scoold/releases/download/1.31.0/scoold-1.31.0.jar
設定ファイルは、Quick Startの内容からGoogleなどのAPI Keyを必要とするものを省き、接続先のParaやScoold自体の参照URLはlocalhost
となるように作成しました。
application.conf
para.app_name = "Scoold"
# the port for Scoold
para.port = 8000
# change this to "production" later
para.env = "development"
# the URL where Scoold is hosted, or http://localhost:8000
para.host_url = "http://localhost:8000"
# the URL of Para - could also be "http://localhost:8080"
para.endpoint = "http://localhost:8080"
# access key for your Para app
para.access_key = "app:scoold"
# secret key for your Para app
para.secret_key = "JZODlJVH1F5pb6vKA6qae8XQYP7MaGOgrXnK3RN6nMZoemSMVmbnag=="
# enable or disable email&password authentication
para.password_auth_enabled = false
# if false, commenting is allowed after 100+ reputation
para.new_users_can_comment = true
# If true, the default space will be accessible by everyone
para.is_default_space_public = true
ここで、para.access_key
とpara.secret_key
は、先ほど作成した新しいアプリケーションの情報を指定します。
こちらも、設定ファイルはTypesafe Configで読み込みます。
起動。
$ java -jar -Dconfig.file=./application.conf scoold-1.31.0.jar
http://localhost:8000
にアクセスすると、起動したScooldの画面を見ることができます。
英語ですけどね!!
日本語化は、次のバージョンでできるのではないかと思いますけどね。
あと、どうやってログインしたらいいんでしょう…?
あれ?ソーシャルログインは?と思われるかもしれませんが、それはScooldの設定で利用をコントロールすることができます。ただ、今回は各種ソーシャル系のキーを用意していないので、パスしています。
Scooldにメールアドレスとパスワードでログインして、質問を投稿しよう
今回は、メールアドレスとパスワードでの認証にしたいと思います。
1度、ParaとScooldを停止してそれぞれのapplication.confを修正します。
通常、メールアドレス認証を行うには、メール通知とverifyが必要ですが、今回はオフにします。
Para側のapplication.conf
# if true, users can be created without verifying their emails
para.security.allow_unverified_emails = true
Scoold側は、メールアドレスとパスワードでの認証を有効にします。
# enable or disable email&password authentication
para.password_auth_enabled = true
この状態でParaおよびScooldを起動すると、Sign inページに行くとログインフォームが現れるようになっています。
Sign upを選んで、ユーザーを登録します。
メールを送ったような画面は経由しますが(ローカルにSMTPサーバーがないので、メール送信に失敗したというエラーログは出ますが…)、この状態でログインできるようになります。
では、質問を投稿してみましょう。
Markdownのプレビュー。
投稿後の質問。
回答を投稿した後。
回答の投稿フォームは、質問のページ内にあります。
Paraの構成を変更する
ここまで、とりあえずということでScooldおよびParaをインストールして簡単に動かすところまでを書いてみましたが、じゃあ実際に利用するにはどうか?というところでは、もう一歩踏み込む必要があります。
ScooldおよびParaでは、データベース、検索エンジン、キャッシュがプラグインになっており、導入環境に合わせて選択することができます。
デフォルトでは、H2 Database、Apache Lucene、Caffeineで動作します。
どのようなものが選べるかは、Paraのドキュメントを見るとよいでしょう。
以下のものから選択することができます。
- データベース
- Apache Cassandra
- DynamoDB
- MongoDB
- RDBMS
- H2 Database
- 検索エンジン
- Elasticsearch
- Apache Lucene
- キャッシュ
- Caffeine
- Hazelcast
ここでは、データベースをMongoDBに変えてみましょう。
$ wget https://oss.sonatype.org/service/local/repositories/releases/content/com/erudika/para-dao-mongodb/1.31.0/para-dao-mongodb-1.31.0-shaded.jar
JARは、プラグインのGitHubのreleaseページより取得しています。
取得したJARを、ParaのJARの中に放り込みます。
$ mkdir -p BOOT-INF/lib
$ mv para-dao-mongodb-1.31.0-shaded.jar BOOT-INF/lib
$ jar -u0f para-jar-1.31.0.jar BOOT-INF
MongoDBは、Dockerで用意しました。
$ docker container run -it --rm --name mongo -p 27017:27017 mongo:4.1
あとは、MongoDBを使うようにParaの設定を変更して、Paraを起動します。
para.dao = "MongoDBDAO"
データベースを切り替えたので、Paraのデータがなくなってしまうので再度/v1/_setup
へのアクセスが必要になります。Scooldに対するキーの取得も、実施してください。
ところで、今回はUber JARを直接更新する形を取りましたが、MavenなどでJAR(もしくはWAR)を再構成するようにしてもOKです。
その場合、ParaのJARやWARの構成を参考に、自分でアーカイブを作成するとよいでしょう。
https://github.com/Erudika/para/blob/v1.31.0/para-jar/pom.xml#L85-L94
https://github.com/Erudika/para/blob/v1.31.0/para-war/pom.xml#L26-L37
ScooldおよびParaの構成的な話
このように、Paraはデータの保存先や検索エンジンなどをプラがブルに変更できるので、構成には柔軟性があります。
ですが、実際に導入するにあたっては、いろいろとカスタマイズしたりしたくなるかもしれません。
最後に少し、ScooldとParaの構成的な面に触れておこうと思います。
Scoold
Spring Boot、Spring Web MVCで構築されたアプリケーションです。主に、以下のフレームワーク、ライブラリで成り立っています。
- Spring Boot(コンテナはJetty)
- Spring Framework
- Apache Velocity
- Typesafe Config
- jQuery
- Materialize CSS
- Font Awesome
- SimpleMDE
また、データを扱う関する機能は一切持たず、データ保存、検索などについてはすべてParaにリクエストを送信することで行っています。
Para
Paraは、DIコンテナにGoogle Guiceを、APIはJerseyを使用して構成されたアプリケーションです。
- Google Guice
- Jersey
- Typesafe Config
- Spring Boot(一部のみ利用、コンテナはJetty)
- Spring Framework
- Spring Security
- flexmark-java
なのですが、なぜか一部Spring Framework系の名前が登場します。サーブレットコンテナだったり、認証まわりでSpringを使用しています。
UIは、一切持ちません。
また、プラグインの仕組みはService Providerの仕組みで構築されています。
ScooldとParaでは、作りがまったく違います。Paraの方が構成的には複雑なのですが、実際にカスタマイズしたい場合はUIなどユーザーに触れる機能を多く持つScooldなのかなと思います。
Paraは、目的がデータ操作と検索に特化しているので、機能自体は割と単純なのです。
自分たちもScooldおよびParaをカスタマイズして使用していますが、カスタマイズの内容の大半はScooldであり、
- 利用する人に合わせたUIの改修、改善
- メール通知の機会の追加
などを行っています。
おわりに
QAサイトを実現するものとして、Stack OverflowクローンであるScooldを紹介しました。構築、インストールするだけなら、そう難しくありません。
ですが、実際に使ってもらえるかは別の話です。
チーム内だったり組織内だったりで使うにも、質問があっても放置されてしまったりすると、どんどん廃れていくのでどうやって文化として根付かせていくのかが大切な気がします。
Scooldに限りませんが、この手のものを導入するのであれば、実際に使う人たちが気軽に質問したり、回答をしてくれるようなプラットフォームになってくれると良いですよね。