クリエイター:メタボ兔

ウェブやアプリの開発者で利用する色な技術やサーバーや開発環境の設定について共有する場

Docker For Macが遅い:対策 - Mutagen編

概要

以前Qiitaに以下のような記事を書いていますが、結果としては満足できなくてRaspberryPiにDockerを動かしてソースをsyncする形で使っていました。

qiita.com

qiita.com

qiita.com

その後Blimpという物を知って簡単なテストしたのが、放置した時間が長かったのかMacOSをアップされたのが原因かわからないが以下のエラーが出て全く解決方法が見つからず。。。

[Error] Get help at https://kelda.io/blimp/docs/help/
Message: Failed to connect to the Blimp cluster
Error: check version: rpc error: code = Unavailable desc = connection error: desc = "transport: Error while dialing dial tcp 34.82.73.248:443: i/o timeout"

Mutagen

Mutagen | Cloud-based development using your local tools

blimpのようにコンテイナーを全部Cloud化する物ではないですが、Volumesをホストのディレクトとコンテナのディレクトリの間に同期してくれる物のようです。

Docker for Macの機能に入っていた

最初みた記事はDocker for MacのEdge channelで、Mutagenが使えるようになった内容でした。

qiita.com

でも、設定画面と現在利用しているバージョン(3.3.1)と違ったので、もうちょっと調べましたら。。。

qiita.com

結果、現在のバージョンには入ってないようですが、Mutagenを使うことには問題がないとのことです。

テスト

環境

Mutagenのインストール

mutage composeコマンドを使用するためにはBeta版をインストールしないといけないようです。

brew install mutagen-io/mutagen/mutagen-beta

docker環境は自分が使用している物から要らない部分を削除して作りました。

Mutagen用 docker-compose.yml作成

元のdocker-compose.yml

version: "3"
services:
  web:
    image: web
    build:
      context: ./web
      dockerfile: Dockerfile
    container_name: web
    ports:
      - "80:80"
      - "443:443"
    command: /sbin/init
    volumes:
      - ../app:/var/www/html:cached
      - ./web/conf.d/extra:/etc/httpd/conf.d/extra:ro
    tty: true
    stdin_open: true
    privileged: true
    restart: always
    depends_on:
      - "php7.3"
      - "dba"
    external_links:
      - "php7.3-fpm"
    logging:
      options:
        max-size: 5m
        max-file: "5"
    networks:
      local-server-net:
        ipv4_address: 172.16.0.2

  dba:
    image: yobasystems/alpine-mariadb
    container_name: dba
    ports:
      - "3306:3306"
    volumes:
      - ./dba/mysql/data:/var/lib/mysql
      - ./dba/my.cnf:/etc/my.cnf
    environment:
      MYSQL_ROOT_PASSWORD: 12345678
      MYSQL_CHARSET: "utf8mb4"
      TZ: Asia/Tokyo
    restart: always
    logging:
      options:
        max-size: 5m
        max-file: "5"
    networks:
      local-server-net:
        ipv4_address: 172.16.0.3

  dns:
    image: dns
    build:
      context: ./dns
      dockerfile: Dockerfile
      args:
        DOCKER_LOCAL_IP: $DOCKER_LOCAL_IP
    container_name: dns
    ports:
      - "53:53/udp"
      - "53:53/tcp"
    volumes:
      - ./dns/dnsmasq.conf:/etc/dnsmasq.conf
      - ./dns/host-names:/etc/host-names
    restart: always
    cap_add:
      - NET_ADMIN
    networks:
      local-server-net:
        ipv4_address: 172.16.0.4

  mailhog:
    image: mailhog
    build:
      context: ./mailhog
      dockerfile: Dockerfile
    container_name: mailhog
    ports:
      - "1025:1025"
      - "8025:8025"
    networks:
      local-server-net:
        ipv4_address: 172.16.0.5

  php7.3:
    image: fpm-php:7.3
    build:
      context: ./php-fpm
      dockerfile: 7.3_Dockerfile
    container_name: php7.3-fpm
    volumes:
      - ../app:/var/www/html
    external_links:
      - "dba"
    ports:
      - '9000'
    networks:
      local-server-net:
        ipv4_address: 172.16.0.8

networks:
  local-server-net:
    driver: bridge
    ipam:
     driver: default
     config:
       - subnet: 172.16.0.0/24

これをmutagen-compose.ymlに変更しました。

version: "3"
services:
  web:
    image: web
    build:
      context: ./web
      dockerfile: Dockerfile
    container_name: web
    ports:
      - "80:80"
      - "443:443"
    command: /sbin/init
    volumes:
      - web_root:/var/www/html:cached
      - web_logs:/var/www/html/storage/logs:cached
      - ./web/conf.d/extra:/etc/httpd/conf.d/extra:ro
    tty: true
    stdin_open: true
    privileged: true
    restart: always
    depends_on:
      - "php7.3"
      - "dba"
    external_links:
      - "php7.3-fpm"
    logging:
      options:
        max-size: 5m
        max-file: "5"
    networks:
      local-server-net:
        ipv4_address: 172.16.0.2

  dba:
    image: yobasystems/alpine-mariadb
    container_name: dba
    ports:
      - "3306:3306"
    volumes:
      - db_data:/var/lib/mysql
      - ./dba/my.cnf:/etc/my.cnf
    environment:
      MYSQL_ROOT_PASSWORD: 12345678
      MYSQL_CHARSET: "utf8mb4"
      TZ: Asia/Tokyo
    restart: always
    logging:
      options:
        max-size: 5m
        max-file: "5"
    networks:
      local-server-net:
        ipv4_address: 172.16.0.3

  dns:
    image: dns
    build:
      context: ./dns
      dockerfile: Dockerfile
      args:
        DOCKER_LOCAL_IP: $DOCKER_LOCAL_IP
    container_name: dns
    ports:
      - "53:53/udp"
      - "53:53/tcp"
    volumes:
      - ./dns/dnsmasq.conf:/etc/dnsmasq.conf
      - ./dns/host-names:/etc/host-names
    restart: always
    cap_add:
      - NET_ADMIN
    networks:
      local-server-net:
        ipv4_address: 172.16.0.4

  mailhog:
    image: mailhog
    build:
      context: ./mailhog
      dockerfile: Dockerfile
    container_name: mailhog
    ports:
      - "1025:1025"
      - "8025:8025"
    networks:
      local-server-net:
        ipv4_address: 172.16.0.5

  php7.3:
    image: fpm-php:7.3
    build:
      context: ./php-fpm
      dockerfile: 7.3_Dockerfile
    container_name: php7.3-fpm
    volumes:
      - web_root:/var/www/html
      - web_logs:/var/www/html/storage/logs:cached
    external_links:
      - "dba"
    ports:
      - '9000'
    networks:
      local-server-net:
        ipv4_address: 172.16.0.8

networks:
  local-server-net:
    driver: bridge
    ipam:
      driver: default
      config:
        - subnet: 172.16.0.0/24

volumes:
  web_root:
  web_logs:
  db_data:

x-mutagen:
  sync:
    defaults:
      ignore:
        vcs: true
    webRoot:
      alpha: "../app"
      beta: "volume://web_root"
      mode: "one-way-replica"
      ignore:
        paths:
          - "./storage/logs"
      configurationBeta:
        permissions:
          defaultFileMode: 0666
          defaultDirectoryMode: 0777
    webLogs:
      alpha: "../app/storage/logs"
      beta: "volume://web_logs"
      mode: "two-way-resolved"
      configurationBeta:
        permissions:
          defaultFileMode: 0666
          defaultDirectoryMode: 0777
    dbData:
      alpha: "./dba/mysql/data"
      beta: "volume://db_data"
      mode: "two-way-resolved"
      configurationBeta:
        permissions:
          defaultFileMode: 0666
          defaultDirectoryMode: 0777

細かい説明は以下の記事をご参考してください。

tech.griphone.co.jp

テスト結果

テストは三つのAPIを5回位実行した後に5回分の時間を記録しました。

Mutagenの未対応

API 機能 1回目 2回目 3回目 4回目 5回目
A Session情報の取得がメイン 1.04s 1.25s 1.03s 1.96s 1.54s
B 設定ファイルから情報を取得がメイン 2.76s 2.56s 3.32s 2.45s 2.12s
C DBから情報を取得がメイン 3.10s 2.75s 3.57s 2.58s 2.38s

Mutagenの対応

API 機能 1回目 2回目 3回目 4回目 5回目
A Session情報の取得がメイン 0.35s 0.81s 0.88s 1.17s 1.36s
B 設定ファイルから情報を取得がメイン 0.83s 0.80s 1.05s 1.39s 1.14s
C DBから情報を取得がメイン 1.16s 1.03s 1.14s 1.20s 1.53s

感想

docker-syncと比べると初期コンテナーの立ち上がる時間が速いし、レスの速度も2倍位早くなった(テストした時のネットが早くなった部分もあり、他の記事では3倍とか)ので良い感じでした。

また、docker-syncの方は同期する際にやっぱりPCに負荷が掛かる印象でしたがmutagenの場合はそれほどでもなかったです。

但し、ネットが繋がらないと使えない弱点もありますね。

Dockerfileで「Ignoring https://dl-cdn.alpinelinux.org/alpine/v3.13/community: temporary error」エラー

エラー発生

使用していたDockerfileが再ビルドしたら突然以下のエラーが発生して来ました。

Step 5/10 : RUN apk --no-cache add dnsmasq
 ---> Running in 9935d2774851
fetch https://dl-cdn.alpinelinux.org/alpine/v3.13/main/armv7/APKINDEX.tar.gz
1996305296:error:0D0D90AD:asn1 encoding routines:ASN1_TIME_adj:error getting time:crypto/asn1/a_time.c:330:
1996305296:error:0D0D90AD:asn1 encoding routines:ASN1_TIME_adj:error getting time:crypto/asn1/a_time.c:330:
1996305296:error:0D0D90AD:asn1 encoding routines:ASN1_TIME_adj:error getting time:crypto/asn1/a_time.c:330:
1996305296:error:0D0D90AD:asn1 encoding routines:ASN1_TIME_adj:error getting time:crypto/asn1/a_time.c:330:
1996305296:error:1416F086:SSL routines:tls_process_server_certificate:certificate verify failed:ssl/statem/statem_clnt.c:1913:
WARNING: Ignoring https://dl-cdn.alpinelinux.org/alpine/v3.13/main: Permission denied
fetch https://dl-cdn.alpinelinux.org/alpine/v3.13/community/armv7/APKINDEX.tar.gz
WARNING: Ignoring https://dl-cdn.alpinelinux.org/alpine/v3.13/community: temporary error (try again later)
ERROR: unable to select packages:
  dnsmasq (no such package):
    required by: world[dnsmasq]
ERROR: Service 'dns' failed to build: The command '/bin/sh -c apk --no-cache add dnsmasq' returned a non-zero code: 1

環境

Dockerfile

FROM alpine

# 外部からの受付とデフォルト値
ARG DOCKER_LOCAL_IP=127.0.0.1

# 変数を環境変数にセット
ENV DOCKER_LOCAL_IP=$DOCKER_LOCAL_IP

RUN apk --no-cache add dnsmasq

RUN mv /usr/sbin/dnsmasq /usr/sbin/dnsmasq-origin
COPY convert2hosts-dnsmasq /usr/sbin/dnsmasq
RUN chmod +x /usr/sbin/dnsmasq

EXPOSE 53 53/udp

ENTRYPOINT ["dnsmasq", "-k", "--log-facility=/var/log/dnsmasq.log"]

原因

最初は単純なネットの不安定かと思いまして何回も実行しましが同じでした。その後調べてみるとこんなイシューがありました。

gitlab.alpinelinux.org

Dockerfileの「FROM alpine」の部分でlatest(3.13.5)が利用されている状況でした。簡単にコンテナから外部へネットがつながるかを試してみます。

# docker pull alpine:3.13
# docker run --rm --name alpine-test alpine:3.13 ping -c3 8.8.8.8
ping: clock_gettime(MONOTONIC) failed
PING 8.8.8.8 (8.8.8.8): 56 data bytes

alpine:3.13.5を利用すると外部のネット(ドメイン)がうまく動かないようですね。

# docker pull alpine:3.12
# docker run --rm --name alpine-test alpine:3.12 ping -c3 8.8.8.8
PING 8.8.8.8 (8.8.8.8): 56 data bytes
64 bytes from 8.8.8.8: seq=0 ttl=113 time=32.343 ms
64 bytes from 8.8.8.8: seq=1 ttl=113 time=8.407 ms
64 bytes from 8.8.8.8: seq=2 ttl=113 time=7.564 ms

--- 8.8.8.8 ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 7.564/16.104/32.343 ms

出来ました!!!

対応

Dockerfileの修正を行いました。

- FROM alpine
+ FROM alpine:3.12

Nexus4(mako)へLineageOS 17(Android 10)をインストール

f:id:FattyRabbit:20210415010522j:plain

概要

私の古いAndroid端末に結構使用しているLineageOSからNexus4(mako)用のLineageOS 17(Android 10)のROMが出たようですので、実際やってみました。

参考:

www.getdroidtips.com

作業前提

以下の作業が完了されている状態で作業を進めてください。

  • Nexus4(mako)のルーティング(Unlock)が完了
  • TWRP Recoveryがインストール完了
  • バックアップが完了(私はTWRP上で完了)

必要なファイルは上記の参考リンクの記事内容を参考してください。

手順

上記の参考リンクの記事内容のとおりにしても実際TWRPでLineageOSのインストールする際にエラーが発生して作業が中止されます。理由はsystemパーティションの容量が原因です。

LineageOS 17をインストールするためには1.5Gが必要(やってみると実際は1.3G位が必要でした。)だそうですが、実際Nexus4はsystemパーティションは900Mにも行かないです。

systemパーティションの再作成

参考:

forum.xda-developers.com

1. PCに接続

"adb devices"のコマンドでNexus4の端末が表示されるか確認します。

2. パーティション作成用のスクリプトをアップロード

Google Driveに共有されているparted.txtをダウンロードして、拡張子(.txt)を削除して置きましょう。その後に以下のコマンドを実行して端末でpartedが実行できるようにします。

# adb push parted /
# adb shell
~ # chmod +x parted

3. 現在のsystemパーティション情報を確認

以下のコマンドでNexus4のパーティション情報が確認できます。

~ # ./parted /dev/block/mmcblk0 p
Model: MMC 016G92 (sd/mmc)
Disk /dev/block/mmcblk0: 15.8GB
Sector size (logical/physical): 512B/512B
Partition Table: gpt

Number  Start   End     Size    File system  Name      Flags
 1      524kB   67.6MB  67.1MB  fat16        modem
 2      67.6MB  68.2MB  524kB                sbl1
 3      68.2MB  68.7MB  524kB                sbl2
 4      68.7MB  70.8MB  2097kB               sbl3
 5      70.8MB  71.3MB  524kB                tz
 6      71.3MB  94.4MB  23.1MB               boot
 7      94.4MB  117MB   23.1MB               recovery
 8      117MB   118MB   799kB                m9kefs1
 9      118MB   119MB   799kB                m9kefs2
10      119MB   120MB   799kB                m9kefs3
11      120MB   121MB   524kB                rpm
12      121MB   121MB   524kB                aboot
13      121MB   122MB   524kB                sbl2b
14      122MB   124MB   2097kB               sbl3b
15      124MB   124MB   524kB                abootb
16      124MB   125MB   524kB                rpmb
17      125MB   125MB   524kB                tzb
18      125MB   126MB   524kB                metadata
19      126MB   143MB   16.8MB               misc
20      143MB   159MB   16.8MB  ext4         persist
21      159MB   1040MB  881MB   ext4         system
22      1040MB  1627MB  587MB   ext4         cache
23      1627MB  15.8GB  14.1GB  ext4         userdata
24      15.8GB  15.8GB  524kB                DDR
25      15.8GB  15.8GB  507kB                grow

説明したとおりsystemが881MBであることが確認できます。

4. パーティションを削除

調整が必要なパーティションをunmountします。

~ # umount /data
~ # umount /sdcard
~ # umount /cache

cacheの容量からsystemパーティションの容量を増やすので、一旦systemとcacheのパーティションを削除します。

~ # ./parted /dev/block/mmcblk0 rm 21
~ # ./parted /dev/block/mmcblk0 rm 22

5. パーティションの再作成

最初のパーティションのStartとEndを以下のように修正する必要があります。

system : 159M ~ 1040M -> 159M ~ 1590M cache : 1040M ~ 1627M -> 1590M ~ 1627M

~ # ./parted /dev/block/mmcblk0 mkpart primary 159 1590
~ # ./parted /dev/block/mmcblk0 mkpart primary 1590 1627

パーティションの名前をつけます。

~ # ./parted /dev/block/mmcblk0 name 21 system
~ # ./parted /dev/block/mmcblk0 name 22 cache

フォーマットします。

~ # mke2fs -b 4096 -T ext4 /dev/block/mmcblk0p21
~ # mke2fs -b 4096 -T ext4 /dev/block/mmcblk0p22

パーティションをmountさせます。

~ # mount -a

終了させます。

~ # exit

Lineage OS 17をインストール

上記にある参考サイトの手順とおりしてLineage OS 17をインストールします。

インストールしたzipファイル

  • Lineage OS : lineage-17.1-20200929-UNOFFICIAL-mako-signed.zip
  • GApps : open_gapps-arm-10.0-nano-20200809.zip

完了した画面

f:id:FattyRabbit:20210415010642p:plainf:id:FattyRabbit:20210415010603p:plainf:id:FattyRabbit:20210415010618p:plain

PHPのバージョン別のDockerfile:バージョン202104

対応概要

ローカル開発環境用で作成したdocker-composeの改善のためにエラーの対応やintlモジュールを追加するためにphp-fpm用のDockefileを修正したので、まとめてみました。

dockerfile

php:7.1-fpm

使用しているphp-fpmのベースにあるOSがバージョンアップされた影響で7.1をサポートしてないxdebugのバージョンがインストールされるのが原因でした。

FROM php:7.1-fpm

RUN apt-get update
RUN apt-get install -y wget libjpeg-dev libfreetype6-dev unzip
RUN apt-get install -y gcc make libjpeg-dev zlib1g-dev mariadb-client libfreetype6-dev libjpeg62-turbo-dev libpng-dev libmcrypt-dev libzip-dev libwebp-dev \
  && docker-php-ext-configure gd --with-freetype-dir=/usr/include/ --with-jpeg-dir=/usr/include/ --with-webp-dir=/usr/include/ \
  && docker-php-ext-configure intl \
  && docker-php-ext-install -j$(nproc) gd zip mysqli pdo_mysql bcmath exif intl

RUN pecl install xdebug-2.9.0 \
  && docker-php-ext-enable xdebug exif

#Composer install
COPY --from=composer /usr/bin/composer /usr/bin/composer

COPY php.ini /usr/local/etc/php/

ENV COMPOSER_ALLOW_SUPERUSER 1

ENV COMPOSER_HOME /composer

ENV PATH $PATH:/composer/vendor/bin

php:7.2-fpm

FROM php:7.2-fpm

RUN apt-get update
RUN apt-get install -y gcc make libjpeg-dev zlib1g-dev mariadb-client libfreetype6-dev libjpeg62-turbo-dev libpng-dev libmcrypt-dev libzip-dev unzip libwebp-dev \
  && docker-php-ext-configure gd --with-freetype-dir=/usr/include/ --with-jpeg-dir=/usr/include/ --with-webp-dir=/usr/include/ \
  && docker-php-ext-configure intl \
  && docker-php-ext-install -j$(nproc) gd zip mysqli pdo_mysql bcmath exif intl

RUN pecl install xdebug \
  && docker-php-ext-enable xdebug exif

#Composer install
COPY --from=composer /usr/bin/composer /usr/bin/composer

COPY php.ini /usr/local/etc/php/

ENV COMPOSER_ALLOW_SUPERUSER 1

ENV COMPOSER_HOME /composer

ENV PATH $PATH:/composer/vendor/bin

php:7.3-fpm

FROM php:7.3-fpm

RUN apt-get update
RUN apt-get install -y gcc make libjpeg-dev zlib1g-dev mariadb-client libfreetype6-dev libjpeg62-turbo-dev libpng-dev libmcrypt-dev libzip-dev unzip libwebp-dev \
  && docker-php-ext-configure gd --with-freetype-dir=/usr/include/ --with-jpeg-dir=/usr/include/ --with-webp-dir=/usr/include/ \
  && docker-php-ext-configure intl \
  && docker-php-ext-install -j$(nproc) gd zip mysqli pdo_mysql bcmath exif intl

RUN pecl install xdebug \
  && docker-php-ext-enable xdebug exif

#Composer install
COPY --from=composer /usr/bin/composer /usr/bin/composer

COPY php.ini /usr/local/etc/php/

ENV COMPOSER_ALLOW_SUPERUSER 1

ENV COMPOSER_HOME /composer

ENV PATH $PATH:/composer/vendor/bin

php:7.4-fpm

FROM php:7.4-fpm

RUN apt-get update \
  && apt-get install -y libfreetype6-dev libjpeg62-turbo-dev libpng-dev libmcrypt-dev zlib1g-dev libicu-dev g++ zip libzip-dev unzip libonig-dev libwebp-dev \
  && docker-php-ext-configure gd --with-freetype --with-webp --with-jpeg \
  && docker-php-ext-configure intl \
  && docker-php-ext-install gd pdo_mysql mysqli mbstring iconv opcache exif intl

RUN pecl install xdebug grpc \
  && docker-php-ext-enable xdebug exif

#Composer install
COPY --from=composer /usr/bin/composer /usr/bin/composer

COPY php.ini /usr/local/etc/php/

ENV COMPOSER_ALLOW_SUPERUSER 1

ENV COMPOSER_HOME /composer

ENV PATH $PATH:/composer/vendor/bin

Laravelのメールアドレスのチェックについて。

概要

昔いphpの言語(ウェブシステム)を始めた時から入力チェックでEmailのチェックが一番悩まされました。

実際入力されたメールアドレスへユーザーの完了メールを送るのが多かったので、正常ではないメールアドレスでRejectメールが管理者アカウントに溜まる気持ち悪い経験をしていました。

こんな事考えていた

じゃ、そうしたらメール形式が合うかどうかと別途チェックが必要ではないか?

参考:メールアドレスを王大人先生に確認してもらう方法(精度に若干の難あり?) | 日記の間 | あかつきのお宿

norm-nois.com

まとめるとメールのドメイン部分を実際DNSに存在していて、MXレコードが登録されているかのチェックすることです。

上記の記事はscoketで25ポートで実際使っているかもチェックしています。

Laravel

ではLaravelのValidatorに追加しよう〜〜と思ったら、既にある!!

Laravel5.8.33のアップデートで追加されたらしいです。5.8の変更項目はみたが...

blog.capilano-fw.com

前提

この機能を使うためにはいくつかPHPintl拡張機能が必要です。

Dockerでのintlをインストール方法は以下の記事をご参考してください。

qiita.com

メールチェック

追加された機能は以下の物です。

email:rfc

RFCと呼ばれるインターネットの標準仕様に合っているかをチェックするバリデーションです。(パッケージの説明では、RFC 5321, 5322, 6530, 6531, 6532が対象となっています)

簡単に言うとメールアドレスの形式があっているかのチェックようです。

 te@st@example.com -> X
 test@example.com -> O

関連クラス:Egulias\EmailValidator\Validation\RFCValidation

email:strict

先ほどの、email:rfcをより厳格にしてもので「エラーだけでなく、警告があってもダメ」なバリデーションになっています。

$email = str_repeat('x', 254).'@example.com'; // xが254個で長すぎる

関連クラス:Egulias\EmailValidator\Validation\NoRFCWarningsValidation

email:dns

DNSにそのメールアドレスのドメインが存在するかをチェックするバリデーションです。例えば、example.comというドメインは存在していますがtest.example.comというものは存在していません。

こちらが実際DNS情報をみて判定するものです。

関連クラス:Egulias\EmailValidator\Validation\DNSCheckValidation

email:spoof

なりすましのメールアドレスは拒否するバリデーションです。 例えば、test@exаmple.comというメールアドレスは見た目は妥当なように見えますが、実はこれは英語のexampleではなく、аに「キリル文字」が使われた偽装ドメインになっています。

関連クラス:Egulias\EmailValidator\Validation\SpoofCheckValidation

email:filter

PHP関数のfilter_var()を使ったメールアドレスのチェックです。

関連クラス:Egulias\EmailValidator\Validation\SpoofCheckValidation

バリデーションは併用できる

Laravelで以下の使い方だとデフォルトではRFCValidation(email:rfc)が適用されます。

'email' => ['required', 'string', 'email', 'max:255', 'unique:users'],

おすすめの使い方としては以下のように使った方がいいかと思います。

'email' => ['required', 'string', 'email:strict,dns,spoof', 'max:255', 'unique:users'],

結論

Laravelすごい〜〜〜〜!!