Docker For Macが遅い:対策 - Mutagen編
概要
以前Qiitaに以下のような記事を書いていますが、結果としては満足できなくてRaspberryPiにDockerを動かしてソースをsyncする形で使っていました。
その後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が使えるようになった内容でした。
でも、設定画面と現在利用しているバージョン(3.3.1)と違ったので、もうちょっと調べましたら。。。
結果、現在のバージョンには入ってないようですが、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
細かい説明は以下の記事をご参考してください。
テスト結果
テストは三つの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
環境
- 機種:raspberry pi 3 model b+
- OS:Linux raspberry2 5.4.51-v7+ #1333 SMP Mon Aug 10 16:45:19 BST 2020 armv7l GNU/Linux
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"]
原因
最初は単純なネットの不安定かと思いまして何回も実行しましが同じでした。その後調べてみるとこんなイシューがありました。
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)をインストール
概要
私の古いAndroid端末に結構使用しているLineageOSからNexus4(mako)用のLineageOS 17(Android 10)のROMが出たようですので、実際やってみました。
参考:
作業前提
以下の作業が完了されている状態で作業を進めてください。
- Nexus4(mako)のルーティング(Unlock)が完了
- TWRP Recoveryがインストール完了
- バックアップが完了(私はTWRP上で完了)
必要なファイルは上記の参考リンクの記事内容を参考してください。
手順
上記の参考リンクの記事内容のとおりにしても実際TWRPでLineageOSのインストールする際にエラーが発生して作業が中止されます。理由はsystemパーティションの容量が原因です。
LineageOS 17をインストールするためには1.5Gが必要(やってみると実際は1.3G位が必要でした。)だそうですが、実際Nexus4はsystemパーティションは900Mにも行かないです。
systemパーティションの再作成
参考:
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
完了した画面
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メールが管理者アカウントに溜まる気持ち悪い経験をしていました。
こんな事考えていた
じゃ、そうしたらメール形式が合うかどうかと別途チェックが必要ではないか?
参考:メールアドレスを王大人先生に確認してもらう方法(精度に若干の難あり?) | 日記の間 | あかつきのお宿
まとめるとメールのドメイン部分を実際DNSに存在していて、MXレコードが登録されているかのチェックすることです。
上記の記事はscoketで25ポートで実際使っているかもチェックしています。
Laravel
ではLaravelのValidatorに追加しよう〜〜と思ったら、既にある!!
Laravel5.8.33のアップデートで追加されたらしいです。5.8の変更項目はみたが...
前提
この機能を使うためにはいくつかPHPのintl拡張機能が必要です。
Dockerでのintlをインストール方法は以下の記事をご参考してください。
メールチェック
追加された機能は以下の物です。
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すごい〜〜〜〜!!