dockerをつかってめっちゃ簡単にモックアップを作れるよ!

@renjikari  です。
この記事は NTTコミュニケーションズ Advent Calendar 2017 の4日目です。~~やったね！間に合ったよ！~~

# TL; DR
- `git clone https://github.com/renjikari/moc_app`
- `docker-compose up`
- `mysql -u root -h 127.0.0.1 < schema.sql`
- and access to http://localhost:5000

# はじめに
　自動化可能な作業(G社風に言えばトイル)や悲しきExcelの連鎖を止めるため、簡単な作業用webアプリを作れないかと打診されることが、今まで何度かありました。
依頼者のほうもどんなものが出来上がるか、もっと言えばそれを作るのに私の稼働を割くべきなのかを判断したいので早めに動くモノがほしいはずです。
いつもはlocalに(個人的にPythonを使いたいので)flaskで適当に書いて１〜２日くらいで作っています。
しかし、このモック作るのもぽちっとできたら楽だなあと思ったので、アドベントカレンダーを締め切りドリブンの理由にして作ってみました。

　おそらくイケてるmockupサービスなどもあると思うのですが、フロントに疎いので使いやすいやつむしろ教えてくださいという感じです。

# 具体的にどんなものを作ったか
以下の観点で作りました。

- サンプルアプリとして、IPaddressを管理するサイトを作成
- Docker EngineとDocker Composeがあれば動くものに
- スキーマを書けるように
- flaskを利用
- Template Engineはjinja2を利用
- すぐに自分が書きたいものを書ける(コピペできる)ようにlogin機構などのform関連などを用意しておく

# モックの中身を紹介
## コード
- コードはここにおいてあります
- https://github.com/renjikari/moc_app

## Dockerについて
- フロントにflaskが立っていて、後ろにMySQLがいるというシンプルな構成です。
- `docker-compose up -d`で起動して下さい
- 止めるときは`docker-compose down`

```yaml:docker-compose.yml
version: '3'
services:
  database:
    image: mysql
    environment:
      - MYSQL_ALLOW_EMPTY_PASSWORD=yes
    ports:
      - "3306:3306"
  app:
    build: .
    container_name: "flask_app"
    ports:
      - "5000:5000"
    volumes:
      - .:/app:cached
    depends_on:
      - database
    tty: true

```
- 上記の通り、MySQLはDocker Hubにあるものを引っ張ってきて、flask側はリポジトリ内のDockerfileからBuildします
- `volumes`で`/app:chached`を使っているのである程度新しいDocker Engine & Docker Composeじゃないと動かないと思います

```Dockerfile:Dockerfile
FROM ubuntu:latest
LABEL maintainer "@renjikari"
RUN apt-get update -y
RUN apt-get install -y python3 python3-pip python3-dev build-essential libmysqlclient-dev
WORKDIR /app
COPY requirements.txt ./
RUN pip3 install -r requirements.txt
ENTRYPOINT ["python3"]
CMD ["app.py"]
```

- flaskはubuntu:latestの中に必要なものを適宜インストールしています。(そこそこ時間かかります)

## schemaについて
- このモックのキモです。エンジニア観点でいうと(私だけ？)モックの時点からスキーマをある程度意識したものが欲しいのでこれがないと作りづらく感じてしまいます。

```sql:schema.sql
DROP DATABASE if EXISTS management_ipaddress ;
CREATE DATABASE management_ipaddress character set utf8mb4;

USE management_ipaddress;

CREATE TABLE ipaddress_list(
    id INT NOT NULL AUTO_INCREMENT,
    ipaddress INT UNSIGNED NOT NULL,
    subnet INT UNSIGNED NOT NULL,
    hostname VARCHAR(255) NOT NULL,
    fqdn VARCHAR(255),
    description VARCHAR(255) NOT NULL,
    updated_at timestamp not null default current_timestamp on update current_timestamp,
    created_by VARCHAR(255) NOT NULL,
    PRIMARY KEY(id)
);

CREATE TABLE users(
    id INT NOT NULL AUTO_INCREMENT,
    username VARCHAR(255) UNIQUE NOT NULL,
    password VARCHAR(255) NOT NULL,
    email VARCHAR(255) NOT NULL,
    PRIMARY KEY(id)
);

insert into ipaddress_list (ipaddress, subnet, hostname, fqdn, description, created_by) VALUE (INET_ATON('192.168.1.100'),24 , "hostname_test", "test.example.com" ,"server for test1", "test_user");
insert into ipaddress_list (ipaddress, subnet, hostname, fqdn, description, created_by) VALUE (INET_ATON('192.168.1.200'),24 , "hostname_test2", "test2.example.com" ,"server for test2", "test_user");
insert into ipaddress_list (ipaddress, subnet, hostname, fqdn, description, created_by) VALUE (INET_ATON('10.0.0.1'),     16 , "hostname_test3", "test3.example.com" ,"server for test3", "test_user");
```

- サンプルとして、management_ipaddressというDBの中にipaddress_listとusersの２つのtableが入っています。
- `mysql -u root -h 127.0.0.1 < schema.sql`を実行すると毎回DBをDROPしてからこのテーブルを作成し、サンプルのカラムを挿入しています
- SQLの書き方をわりと毎回ぐぐってるのでサンプルで残しておきたいと思い、使いそうなやつを入れています。
    - timestampとか
    - UNSIGNED & INET_ATONとか

## flaskについて
- webappは以下から構成されています。
    - login用のページ
    - login先のホーム画面
- 実際にwebappでできることは以下です。
    - loginページにてuserを作成できる
    - 作成したuserでloginできる
    - login先のページでipaddressのリストを閲覧できる
    - login先のページでipaddressのリストを追加できる

## loginページ
- 下記のスニペットをほぼそのまま使っています。
    - https://bootsnipp.com/snippets/featured/login-and-register-tabbed-form
- タブでloginとregisterを切り替えられるシンプルなログイン画面


## login先のページ(ソースではhome.html)
- 下記のブートストラップのサンプルを改造して使っています。
    - https://getbootstrap.com/docs/3.3/examples/dashboard/
- すぐにコピペできるよう以下の要素を入れています。
    - jinja2上でのforループ、if分岐
    - bootstrapにおけるformやtableの書きっぷり

# 飽きてきて未回収のところ
- passwordはsha256でhash化してdbに入れていますが、session機能は~~めんどくなって~~実装してません
- users テーブルのusernameをUNIQUEにしたんですが、app側でとくに処理をしていないため、同じusernameのuserを作ろうとすると普通にエラーが返ってきます
- こんなサンプルアプリ書いといて何ですが、IP addressをDBで扱うならPostgresSQLで書いたほうが分かりやすい気がします(inet型最高説)

# 終わりに

- 最近またちょっとサーバエンジニアをやっていたのでpythonとかフロント書くの楽しかったです。(ちょっとしか書いてないとか言わない)
- まじで3コマンド打てばflaskでモック作れる(別に本番用に使っても良いんだよ)のでぜひ使ってみてくれるとうれしいです
- 時間があればPostgreSQL版とかSinatra版とかGO版とか書きたいので**PRお待ちしております**