PHP+msmtpとMailCatcherをDockerで動かす

PHP+msmtpとMailCatcherをDockerで動かす

今までPHP+ssmtpとMailCatcherを使用していた。

WSL2にしてDockerを動かそうとしたら

Package 'ssmtp' has no installation candidate

と出てインストールできなかった。

ssmtpはメンテされていないことを知ったので代わりにssmtpからmsmtpを使用することにした。

PHP + msmtpコンテナからメールを送信してMailCatcherコンテナで受信するイメージ。

MailCatcherを立ち上げる

参考 qiita.com

msmtp

PHPのコンテナのDockerfileに以下を追加。

RUN  apt-get install msmtp msmtp-mta -yqq

msmtp設定ファイルの場所

root@819b134ed4c4:/# msmtp --version
msmtp version 1.8.3
Platform: x86_64-pc-linux-gnu
TLS/SSL library: GnuTLS
Authentication library: GNU SASL
Supported authentication methods:
plain scram-sha-1 external gssapi cram-md5 digest-md5 login ntlm
IDN support: enabled
NLS: enabled, LOCALEDIR is /usr/share/locale
Keyring support: none
System configuration file name: /etc/msmtprc
User configuration file name: /root/.msmtprc

Copyright (C) 2019 Martin Lambers and others.
This is free software.  You may redistribute copies of it under the terms of
the GNU General Public License <http://www.gnu.org/licenses/gpl.html>.
There is NO WARRANTY, to the extent permitted by law.

システムの設定ファイルは /etc/msmtprc
ユーザ個別の設定ファイルは /root/.msmtprc

  • 設定ファイルをコンテナにマウントする
    volumes:
      - ./msmtprc:/etc/msmtprc
  • msmtprcの設定
/etc/msmtprc
# Set default values for all following accounts.
defaults
auth off
tls off
tls_trust_file /etc/ssl/certs/ca-certificates.crt
syslog on
aliases /etc/aliases

# MailCatcher
account mailcatcher
# MailCatcherのコンテナ名
host mailcatcher
port 1025
from username@example.com
user username
password password

# Set a default account
account default : mailcatcher

auth と tls をoffにしないと以下のエラーが出て送信できない。

msmtp: the server does not support TLS via the STARTTLS command
msmtp: could not send mail (account default from /etc/msmtprc)

msmtp: the server does not support authentication
msmtp: could not send mail (account default from /etc/msmtprc)

送信

$ echo "Hello this is sending email using msmtp" | msmtp recipent@domain.com

php.iniの設定

[mail function]
; For Win32 only.
; http://php.net/smtp
SMTP = localhost
; http://php.net/smtp-port
smtp_port = 25

; For Win32 only.
; http://php.net/sendmail-from
;sendmail_from = me@example.com

; For Unix only.  You may supply arguments as well (default: "sendmail -t -i").
; http://php.net/sendmail-path
;sendmail_path = /usr/sbin/sendmail -t -i
sendmail_path = "/usr/bin/msmtp -C /etc/msmtprc -t"

PHPから送信

<?php
     mail("your@email.com", "Test email from PHP", "msmtp as sendmail for PHP");
?>

参考

『達人に学ぶDB設計徹底指南書』を読んだ

達人に学ぶDB設計 徹底指南書 初級者で終わりたくないあなたへ

達人に学ぶDB設計 徹底指南書 初級者で終わりたくないあなたへ

DB設計をする上で必要な知識が詰まっている本だった。もっと早く読んでおくべきだった。マストです。
唯一の正解などなく、整合性・パフォーマンスのトレードオフとコストの問題を考えて適切な選択をすること、それこそがDBエンジニアの腕の見せ所であるということを学んだ。
以下、まとめ。

DOA データ志向アプローチ

設計を制する者はシステム開発を制す。それはシステムがデータのフォーマットに合わせて作られるから(システムに合わせてデータを作るのではない)。

データベースデータ設計がシステムの品質を最も大きく左右する。ソフトウェアというのは、言ってみれば「データの流通機構」であって、どのようなプログラムが必要になるかは、どのようなデータをどういうフォーマットで設計するかに左右される。

データベースを制する者がシステムを制す。データベースは、システムの中心であると同時に、システム開発の中心でもある。

システム開発の素人に、予備知識を何も与えないままで開発を行なわせると、ほぼ十中八九がプログラムから設計を始めます。

3層スキーマについて復習

スキーマ=データ構造やフォーマット
外部スキーマ(外部モデル)=ビューの世界
概念スキーマ(論理データモデル)=テーブルの世界
内部スキーマ(物理データモデル)=ファイルの世界

概念スキーマ

開発者から見たデータベース。
概念スキーマを定義する設計=論理設計。
論理設計は物理設計に先立つ。
「論理」とは物理層の制約(データベースサーバの性能など)に縛られないという意味。

論理設計のステップ

エンティティの抽出→エンティティの定義→正規化→ER図の作成

エンティティの抽出

エンティティとは現実世界に存在するデータの集合体を現す言葉。日本語だと「実体」を意味するが物理的実体を伴っているとは限らない。「社員」や「注文履歴」など。
システムのためにどのようなエンティティが必要になるのか、どのようなデータを扱う必要があるのかを考える作業。要件定義と重なる。エンティティはデータを「属性(attribute)」という形で保持する。

内部スキーマ

テーブルやインデックスの物理定義。物理設計。

物理設計のステップ

テーブル定義→インデックス定義→ハードのサイジング→ストレージの冗長構成の決定→ファイルの物理配置決定

サイジング全般

データベースにおいては、データの整合性とパフォーマンスの間に強いトレードオフが存在します。つまり、整合性を高くしようとするとパフォーマンスが犠牲になり、パフォーマンスを追求すると整合性を犠牲にする、という二律背反の原則です。データベース設計とは、限られた予算制約の中で、両端の間の平衡点を見つけ出そうとする努力だと言っていいでしょう。

サイジングはパフォーマンスを決定する。性能問題のほとんどはストレージのIOネックから引き起こされる。

ディスクの見積もり

データベース内に格納するデータ量は物理的なテーブル定義とインデックス定義が終わらなければ計算できない。

パフォーマンスのサイジング

処理時間・スループットを要件定義の段階で決めておく

サイジングは物理設計の中でも難易度の高いタスクなのですが、これがこなせるようになればDBエンジニアとしてはエース級です。

論理設計もろくにできていない段階で「DBサーバを何台くらい必要か」「費用はいくらかかりそうか」などと聞かれて困っていたが答えられなくて当然なのだなと安心した。
クラウドの利用によってDBサーバの増減が容易になってきてはいるが、性能要件やコストを考えてバランスをとることを考えるとサイジングは未だに難しそう。スケールアウトできるような設計になっていることが前提だけど。

論理設計と正規化

テーブル名の命名規則
アルファベット+数字+アンダーバー
ハイフンは使ってはいけない
またテーブル名の先頭を数字から始めてはいけない

正規化とはなにか

正規形とはデータの冗長性を排除し一貫性と効率性を保持するためのデータ形式
冗長性や一貫性がないと、同じデータが複数のテーブルに存在して無駄なデータと更新処理が発生する、データの整合性が取れないなどの問題が発生する。

こうした更新時の不整合の問題を解決するために正規化を行う。

第一正規化

繰り返し要素の排除。主キーによって一意にデータを特定できるようにする。

・関数従属性とは
入力Xに対して出力Yを一つに決めるもの。YはXに従属する。
Xの値が決まるとYの値が一意に決まる

デジタル大辞泉の解説
かん‐すう〔クワン‐|カン‐〕【関数/×函数
1 《function》二つの変数x、yがあって、xの値が決まると、それに対応してyの値が一つ決まるとき、yはxの関数であるという。
https://kotobank.jp/word/%E9%96%A2%E6%95%B0-2523

第2正規化

主キーの一部の列に対して従属する列がある部分従属関数の排除

第3正規化

主キー以外の列の推移的関数従属の排除

[SQL] 16. データベースの設計 2 | TECHSCORE(テックスコア)
I-22-10. データベース正規化の具体的な考え方と手順 | 日本OSS推進フォーラム

基本的に第3正規化まで行うべき。パフォーマンスなどの問題があるなら非正規化する。

正規化によってテーブルが分割され整合性が担保されるが、テーブルの結合が行われることによってパフォーマンスが下がる。
サマリデータを冗長に保持すると正規形に違反するが検索を高速化できる。

「非正規化」はあくまでも最後の手段であるという姿勢でのぞむ、というものだ。要するに、十分に正規化された設計をあきらめてもよいのは、パフォーマンスを向上させるためのその他すべての戦略が要件を満たさない場合だけである。

f:id:kyamashiro:20190630110155g:plain
I-22-10. データベース正規化の具体的な考え方と手順 | 日本OSS推進フォーラムより引用

非正規化の状態から正規化するときでも同じなのですが、ともあれ、論理設計をする際には「システムの品質は(ひいては開発が成功するかどうかは)今ここで決まる!」という気概を持って臨む必要があります。かつ、論理設計を担当する人間は、正規形の理論を理解しているだけでなく、それによって生じる様々なトレードオフを知り尽くしたうえで、あらゆる要件を同時に満たせる平衡点を探し出せる能力が必要とされるのです。

データモデルの後からの変更は影響範囲が大きい・・・。

インデックス

B-treeインデックスはO(logn)
フルスキャンは O(n)

ソートはコストが高い

ソートというのは、かなりコストの高い演算です。ソートはDBMS内部で専用のメモリ領域が割り当てられており、その内部に一時的にデータを保持して実施されますが、大量データのソートが必要な場合、メモリに載りきらないためにあふれてしまうことがあります。その場合、DBMSは一時的にディスクへデータを書き出します。この場合のI/Oコストが非常に大きなものになるのです。したがって、SQL文を記述する際は、極力大きなソートを避けることがパフォーマンス上は望ましい、ということになります。

インデックスをつけるときは1.データ量、2.カーディナリティ、3.選択条件・結合条件に使用されるカラムを考慮する。

  1. データ量の目安は1万件。
  2. カーディナリティの目安は全体のレコード数の5%に絞り込めるだけのカーディナリティがあるかどうか。つまり値がうまく平均的に分散していれば効果が高い。
  3. インデックス列に以下の適用をしていないこと
  • 演算していないこと
  • SQL関数を使用していないこと
  • IS NULLを使用している

IS NULLはインデックスを使うのか - istyle Tech Blog
MySQL :: MySQL 5.6 リファレンスマニュアル :: 8.2.1.8 IS NULL の最適化

  • 否定形を使用している
  • ORを使用している
  • 後方一致・中間一致のLIKE演算子を使用している
  • 暗黙の型変換を行っている
  • インデックスの順番が適切であること

B-treeインデックスは更新していくとバランスが崩れて性能が劣化する。
第6回 パフォーマンスの基礎である索引について
より高速なデータアクセスのために最適なインデックスを選択して作成する - ベストプラクティス| Alibaba Cloud ドキュメントセンター

アンチパターン

情報は可能な限り分割したほうが良い
分割されたものを結合することはできるが結合されたものを分割することは難しい。例えば名前を保存する場合姓カラムと名カラムで分割する。

プログラミングおよびシステム開発という仕事全体が、データによって規定されるからです。下手くそなデータ構造に対して、エレガントなプログラミングを行なうことは不可能なのです。データ構造がダメな状態で、プログラミングによって挽回することはできません。システム開発において最も重要なのは、コーディングではなくデータ設計なのです。

代理キー問題

一般的な原則としては、極力代理キーの使用は避けて、自然キーによる解決を図るべきです。その主な理由は、代理キーがそもそも論理的には不要なキーのため、論理モデルをわかりにくくしてしまうからです。

ジョー・セルコは「オートナンバーを主キーに使うことは、データモデルを欠いている証拠だ」と、自然キー以外を主キーに使うことを厳しく批判しています。

フレームワークのmigrationを使うと自動でidがつくので、int型のAUTO INCREMENTのidカラムを主キーにしたテーブルを多用していたのだがこれはよくなかったのだろうか。複合主キーにするべきだったのか。トレードオフの問題なのか。
漢(オトコ)のコンピュータ道: ナチュラルキーとサロゲートキーについての議論
【DB】 サロゲートキー(代理キー)の初歩

やる気が出ない原因がわかった

今週はあまりやる気が出ず集中力もなかったと思う。ただ原因がわからなかった。

今日も朝起きてから写経して、疲れて昼寝したけど体が重い感じがしてさっぱり疲れが取れている感じがしなかった。

昨日は仕事中に夕方ぐらいから腰が痛くなって、それはずっと座っているからであって自分としてはよく起こることではある。会社の椅子が自分に合わないということもあるが。

昼寝から起きた後も腰に鈍い痛みがあるので背中をマッサージしてもらって気づいたけど、やる気が起こらなかったのは「呼吸が浅い」ことが原因なのではないかということ。マッサージが終わった後で呼吸をしてみると肺に酸素が行き渡っている感覚があってとてもスッキリした。

思い返せば今週はやたらとため息をついていた。ため息が出るのはやる気が起こらないからだと思っていたけど、実は呼吸が浅くて体が無意識にため息を引き起こしていたからではないか。

 

姿勢が悪い→呼吸が浅くなる→やる気が起きない+疲れが取れない

 

こういう悪い循環はおそらく運動不足と姿勢が悪いという問題から生じている。これはなんとかしたい。「やる気が起きない問題」は毎日継続した努力を目標にしている自分にとっては深刻。

というわけで車も人通りも少ない早朝にクロスバイクに乗って運動するかな。あとこういう姿勢をよくするサポーターでも買って改善するか。。。

大して知識もないのにAPI設計するときに役立つサイト一覧

RESTについて

yohei-y:weblog: REST 入門

JSONについて

JSON データの操作 - Web 開発を学ぶ | MDN

Google JSON Style Guide

ステータスコード

結構悩むステータスコードについて

HTTP レスポンスステータスコード - HTTP | MDN

【図解】RESTful WebサービスにおけるHTTPステータスコード : アジャイル株式会社

RESTful API設計におけるHTTPステータスコードの指針 - Qiita

WebAPIでエラーをどう表現すべき?15のサービスを調査してみた - Qiita

OAuth

The OAuth 2.0 Authorization Framework: Bearer Token Usage(日本語)

OAuth 認証を真面目に考える | DevelopersIO

OAuth 2.0 の仕組みと認証方法 | murashun.jp

一番分かりやすい OAuth の説明 - Qiita

OAuth2.0とOpenID Connectの概要 - Qiita

API設計について

API 設計ガイド  |  Cloud API  |  Google Cloud

API 設計ガイダンス - Best practices for cloud applications | Microsoft Docs

APIテクニカルガイドブック 2019年(平成31年)3月28日 内閣官房情報通信技術(IT)総合戦略室

翻訳: WebAPI 設計のベストプラクティス - Qiita

WebAPIの設計から実装まで〜設計編〜 - Qiita

APIドキュメントツール

1. API Blueprint

API Blueprint を使って Web API の仕様書を書こう (フェンリル | デベロッパーズブログ)

【API Blueprintの使い方】Web APIの仕様書を書く・読む・実行する | DevelopersIO

2. Swagger

開発効率を上げる!Swaggerの記法まとめ - ZOZO Technologies TECH BLOG

Swaggerの記法まとめ - Qiita