モヒカンメモ

髪色が定期的に変わることに定評のある(比較的)若者Webエンジニアの備忘録

useraddコマンドをAmazon Linux2へインストールする

Linuxユーザを追加するときに使うuseraddコマンド。Amazon Linux2のdockerイメージではデフォルトでは入っていなかったのでインストール方法を調べたたときの備忘録。Amazon Linux2に限らず、Linuxのminimal環境にuseraddコマンドを入れるのに使える方法だと思う。

useraddコマンド

 「useradd」は新規ユーザーを作成し、ユーザーごとの設定を決めるコマンドです。作成時のデフォルト値をあらかじめ定めておくこともできます。

www.atmarkit.co.jp

Amazon Linux2 dockerイメージ

Amazon Web ServicesのEC2でインスタンスを立てるときによく使われる Amazon Linux2 のdocker imageがdockerhubに上がっていた。

hub.docker.com

f:id:pinkumohikan:20200704121521p:plain
Amazon Linux2のdocker image

$ docker run --rm -it amazonlinux:2 bash
bash-4.2# cat /etc/os-release | grep PRETTY_NAME
PRETTY_NAME="Amazon Linux 2"

ただ、実際のAmazon Linux2 AMIとはインストールされているパッケージとかが若干の差異があるみたい。sudoとかuseraddとかsystemdとか入ってないし、minimal版みたいな感じっぽい。

デフォルトではuseraddコマンドが入っていない

Amazon Linux2向けのプロビジョニングを書いていて、ユーザの追加とかやりたかったんだけどuseraddコマンドが入っていない。

bash-4.2# useradd
bash: useradd: command not found

適当にググったら shadow-utils っていうパッケージに内包されているらしい。

シャドウパスワードファイルとユーザー/グループアカウントを管理するための ユーティリティ。

penguin.triumf.ca

$ docker run --rm -it amazonlinux:2 bash
bash-4.2# cat /etc/os-release | grep PRETTY_NAME
PRETTY_NAME="Amazon Linux 2"
bash-4.2#
bash-4.2#
bash-4.2# yum list shadow-utils
Loaded plugins: ovl, priorities
amzn2-core                                                         | 3.7 kB  00:00:00
(1/3): amzn2-core/2/x86_64/group_gz                                | 2.5 kB  00:00:00
(2/3): amzn2-core/2/x86_64/updateinfo                              | 223 kB  00:00:00
(3/3): amzn2-core/2/x86_64/primary_db                              |  42 MB  00:00:03
Available Packages
shadow-utils.x86_64                   2:4.1.5.1-24.amzn2.0.2                    amzn2-core

yumリポジトリの追加要らずでシュッとインストールできそう。

shadow-utilsをインストールする

bash-4.2# yum install -y shadow-utils
Loaded plugins: ovl, priorities
amzn2-core                                                         | 3.7 kB  00:00:00
(1/3): amzn2-core/2/x86_64/group_gz                                | 2.5 kB  00:00:00
(2/3): amzn2-core/2/x86_64/updateinfo                              | 223 kB  00:00:00
(3/3): amzn2-core/2/x86_64/primary_db                              |  42 MB  00:00:04
Resolving Dependencies
...
Installed:
  shadow-utils.x86_64 2:4.1.5.1-24.amzn2.0.2

Dependency Installed:
  audit-libs.x86_64 0:2.8.1-3.amzn2.1         libcap-ng.x86_64 0:0.7.5-4.amzn2.0.4
  libsemanage.x86_64 0:2.5-11.amzn2           ustr.x86_64 0:1.0.4-16.amzn2.0.3

Complete!

useraddが使えるようになった🎉

bash-4.2# useradd
Usage: useradd [options] LOGIN
       useradd -D
       useradd -D [options]

Options:
...

めでたしめでたし

80番ポートを使っているプログラムをlsofコマンドで特定する

Linux環境で特定のポートを使いたいけど先に使われていてどのプログラムがそのポートを使っているか知りたいとき、lsofコマンドが便利。

lsofコマンド

 「lsof」はオープンしているファイルを一覧表示するコマンドです。

www.atmarkit.co.jp

lsofコマンドに-iオプションでポート番号をつけて実行すると、そのポートを握っているプログラム (コマンド) がわかる。

80番ポートを使っているのは誰?

$ sudo lsof -i:80
COMMAND   PID     USER   FD   TYPE   DEVICE SIZE/OFF NODE NAME
nginx   17287     root   12u  IPv4 47601898      0t0  TCP *:http (LISTEN)
nginx   17287     root   14u  IPv6 47601900      0t0  TCP *:http (LISTEN)
nginx   17292 www-data   12u  IPv4 47601898      0t0  TCP *:http (LISTEN)
nginx   17292 www-data   14u  IPv6 47601900      0t0  TCP *:http (LISTEN)
nginx   17293 www-data   12u  IPv4 47601898      0t0  TCP *:http (LISTEN)
nginx   17293 www-data   14u  IPv6 47601900      0t0  TCP *:http (LISTEN)

この例ではnginxがTCP 80番 (http) を握っていることが読み取れる。

Nginxに "413 Request Entity Too Large" と怒られる原因と対処法

Nginxをリバースプロキシとして使っている環境でファイルアップロードなどを行おうとしたとき "413 Request Entity Too Large" というエラーレスポンスが返ることが有る。

nginx.org

f:id:pinkumohikan:20200526235206j:plain
413 Request Entity Too Large

原因

Nginxへ送信されたコンテンツのサイズが大きすぎて、制限を超えているため。

HTTP Response Status Code 413の定義は下記:

6.5.11. 413 Payload Too Large

The 413 (Payload Too Large) status code indicates that the server is refusing to process a request because the request payload is larger than the server is willing or able to process. The server MAY close the connection to prevent the client from continuing the request.

tools.ietf.org

意訳: 413はリクエストがでかすぎてサーバが拒否ったことを示すステータスコードだよ。

※ RFC的には "Payload Too Large" って定義されているけど、Nginxは "Request Entity Too Large" って返してるの何でだろう?知っている人いたら教えて下さい。

対処法

方法としてはざっくり、制限内で収まるようにリクエストサイズを制限する方法と、Nginxの設定を変更してリクエストサイズの上限を引き上げる方法がある。

1. 制限内で収まるようにリクエストサイズを小さくする方法

レンタルサーバを使っている場合など、Nginxの設定を変更する権限がない場合にはこうするほか無さそう。現状の設定を確認して、それに収まるようにリクエストサイズを小さくする。

例えばファイルアップロード機能で怒られる場合は、アップロードできるファイルサイズをNginxが許容するサイズ以下になるようUI側で制限する。具体的な方法としてはFile APIなどが使えそう。

developer.mozilla.org

2. Nginxの設定を変更してリクエストサイズの上限を引き上げる方法

Nginxの設定を変更する権限がある場合、設定ファイルの client_max_body_size というパラメータを変更することでリクエストサイズの上限を引き上げられる。デフォルトでは1MBと結構タイト。

nginx.org

Syntax: client_max_body_size size;

Default: client_max_body_size 1m;

Context: http, server, location

Sets the maximum allowed size of the client request body, specified in the “Content-Length” request header field. If the size in a request exceeds the configured value, the 413 (Request Entity Too Large) error is returned to the client. Please be aware that browsers cannot correctly display this error. Setting size to 0 disables checking of client request body size.

意訳: クライアントが送ってくるリクエストボディサイズの上限を設定する。リクエストのContent-Lengthが設定値を超えていたら 413 (Request Entity Too Large) エラーをクライアントへ返すよ。0を指定したらサイズをチェックしないよ。

ただし、設定を変更する前に、現状の設定がどういった意図でされているものかを確認するべし。単にデフォルトのままとかであれば変えて良さそうけど、例えばサーバのスペックと想定同時アクセス数などを勘案してリクエストサイズを制限している場合、むやみに設定を変えるとサーバがトラフィックに耐えられなくなる恐れがある。

f:id:pinkumohikan:20200526234900p:plain
50MBまで許す設定の例

設定を書き換えてNginxをreloadしてあげれば、もう怒られない。

f:id:pinkumohikan:20200526235219j:plain
200 OK。もう大きなファイルを上げても怒られない

FileReader.readAsDataURLで得られるのはData URIであって純粋なbase64文字列じゃないぞ

ファイルをFileReader.readAsDataURLを使って文字列化したものは純粋なbase64文字列だと思っていたけど、decodeしようとしたら出来なくてなんでやねん!と思ったので残しておく。

まとめ

  • 画像とかの添付ファイルをJavaScriptで扱うときにFileReaderを使う
  • FileReader.readAsDataURLのresultで得られるのはData URIであって、純粋なbase64文字列じゃない
  • 先頭のData URI宣言部を取り除いたら純粋なbase64文字列になる

大事なことは全部ドキュメントが教えてくれた

base64 decodeできなくて「おや?」と思ったけど、大事なことは全部ドキュメントに書いてあった。

developer.mozilla.org

メモ: blob の result は、先に Base64 でエンコードされたデータの前にある Data-URL の宣言を削除しておかないと、直接 Base64 としてデコードすることができません。 Base64 でエンコードされた文字列のみを受け取る場合は、先に結果から data:/;base64, を削除しておく必要があります。

resultの文字列をprintしてみたら data:image/jpeg;base64,/9j/2wCEAAgGB... みたいな感じになっていて、たしかにbase64文字列じゃないや。っていうかよくよく考えればメソッド名が readAsDataURL だから、実行結果として得られるものは当然Data URIだよな... 😇

余計な文字列を取り除く

文字列化したものをWeb API等へ送るときは、先頭の余計な文字列を取り除いておこう。

実際に取り出した文字列をみるに data:${mimeType};base64,${base64EncodedFile} という構造になっていそうだけど、ドキュメントに 先に結果から data:*/*;base64, を削除しておく必要があります とあるのでとりあえずそれに従えば良さそう。

こんな感じ:

const dataURI = filereader.result; // "data:image/jpeg;base64,/9j/2wCEAAgGB..." みたいなのが入る
const base64EncodedFile = dataURI.replace(/data:.*\/.*;base64,/, '');

developer.mozilla.org

海外へWebコンテンツを配信する際はアクセシビリティの法律に気をつけるべし

ふとしたtweetをきっかけに、海外向けにWebコンテンツを配信する際には現地のアクセシビリティに関する法律に気をつける必要があることを学んだ。

ざっくりまとめ

  • アメリカ等、国によってはアクセシビリティが権利として法的に認められている
  • 先の法を根拠に年間2000件以上の訴訟が起きている
  • 日本ではアクセシビリティは努力目標だけど、同じ感覚で海外展開すると危険

アクセシビリティとは

情報システムの利用しやすさを表す言葉。パソコンやインターネットが幅広く普及した現在、高齢者や障害者などハンディを持つ人にも健常者と同じように使える環境を整える必要がある。アクセシビリティはその対応度を計る尺度となるもの。具体的には「画像や音声などには代替表現として必ずテキストによる注釈をつける」「マウスの使用が困難な人向けにすべての操作をキーボードで行なえるようにする」ことなどが求められている。

kotobank.jp

ざっくり言うと、みんながみんな同じように画像を認識し、文字が読めるわけではないから、そういう境遇の人でもコンテンツを享受できるように配慮してね、みたいなやつ。マルチデバイス対応とか音声読み上げへの対応が代表例。

日本にも、Webコンテンツのアクセシビリティに関するJIS規格があるらしい。

waic.jp

国によってはアクセシビリティが権利として認められている

webtan.impress.co.jp

今回の学びの大部分は上記記事からのもの。特に学びが有ったところを下記に抜粋。

アメリカには、障害を持つ人がアメリカ社会に完全に参加できることを保証したADA(Americans with Disabilities Act 障害を持つアメリカ人法)という法律があります。このADAに基づいたWebアクセシビリティ提訴の件数が、2017年には814件だったのが2018年には2,285件となり281%も増加しています。

...

弁護士の手配や証拠開示手続き、交渉などを含めると、訴訟1件あたりの費用の試算は356,775ドル(約4,000万円)にものぼるとのことです。

...

アメリカでは、5人に1人(=6,400万人)がなんらかの障害を持っており、障害のある就労年齢の人々の可処分所得合計は約4,900億ドル。アフリカ系アメリカ人は5,010億ドル、ヒスパニック系アメリカ人は5,820億ドルとなっており、他の重要な市場セグメントに匹敵することことも紹介していました。

...

アメリカの場合は法律で「やれ」と定められており、アクセシビリティ対策をしないという選択肢はそもそもないらしい。というよりむしろマーケットとしてそれなりに大きいのでアクセシビリティへの積極投資に経済的合理性があるらしい。

こと日本においてはアクセシビリティ対策は努力目標の位置づけだけど、海外では権利として認められているところもあるので海外展開する際に日本と同じ感覚でいると危ないことは覚えておきたい。

Lambda@Edgeではオリジンのデータを部分的に書き換えて返すことはできない

ちょっと何を言っているか分からないと思うけど、自分も分かりたくなかった!

ざっくりまとめ

  • AWS CloudFrontにはいわゆるエッジコンピューティングを提供する Lambda@Edge がある
  • Lambda@Edgeではオリジンから返ってきたbodyの一部を書き換えて返すことは(パパッとは)できない

bodyどこーーー

Lambda@Edgeとは

aws.amazon.com

AWSが提供するCDNサービスCloudFrontに付随する、エッジコンピューティングサービス。配信先のユーザに近いサーバでLambdaを実行して結果を返したら速くコンテンツ提供できるよねーというやつ

ESI (Edge Side Includes) やりたいとか、基本静的コンテンツしか返さないんだけどごく一部で動的にしたいんだよねーでもpathは変えたくないしサーバも用意したくないんだよねーみたいなときに使えそうなやつ

やりたかったこと

CloudFront + S3な構成において、特定のリクエストパラメータが指定された場合にコンテンツの一部を書き換えて配信したい

例えば、S3におっきなjson置いといて ?limit=10&page=1 みたいなクエリパラメータがついていたらjsonの一部だけを返す、みたいな感じ

GET /posts

Response:
{
    "posts": [
        // たくさんのPost
    ]
}
GET /posts?limit=10&page=1

Response:
{
    "posts": [
        // id 1 - 10までのPost
    ]
}

Lambda 関数をトリガーできる CloudFront イベント を呼んで、下記の図でいう Origin Response をトリガーにLambda@Edgeを動かせばやりたいことできそうだと思うじゃん?

https://docs.aws.amazon.com/ja_jp/AmazonCloudFront/latest/DeveloperGuide/images/cloudfront-events-that-trigger-lambda-functions.png

Lambda@Edge 関数の例 とか見てもRequestとResponseそれぞれいじっているようなコードがポコポコ書かれてるし、テンプレートエンジンのレンダリングとかに使えるんじゃねみたいな記事もどこかで見かけたし、絶対行けそうだと思うじゃん????

オリジンから返ってきたbodyはLambda@Edgeで読めない

雑にPoCコード書いてたら、衝撃の事実に気づく

イベントの構造 レスポンスイベント

response event

おわかり頂けただろうか?

response headerはしっかり渡ってくるけど、 response bodyは渡ってこない!!! ママ〜!!!!!!!!

いやいやそんなばかなー、と思ってググったら「それ仕様やで」っていうクラメソの記事もヒット

dev.classmethod.jp

やっぱりそういうことらしいですわ。ぐぬぬー

じゃあどうすんの?

任意のbodyを返すことは出来るので、response bodyが渡って来ないならしょうがないから自分でS3 getするしかない。でも、トリガーが Origin Response のままだとCFがS3 getしたあと自分でもS3 getする感じになって無駄なので、トリガーを Origin Request に変えて、

  • 所定のパラメータがついていなかったらオリジンにそのまま問い合わせさせる
  • 所定のパラメータがついていたら自分でS3 getしてフィルタリング、オリジンに問い合わせさせずにresponseを返す

って感じにするのがスマートかなあ。

リクエストトリガーでの HTTP レスポンスの生成

もしもっといい方法があったらマジで教えて下さい!

っていうか何でこんな仕様になってるの?教えてエロい人

Amazon Linux 2へPHP7.4をインストールする

Amazon Linux 2へPHP 7.4をインストールしたので備忘録がてら残しておく。

f:id:pinkumohikan:20191228190238p:plain
PHP 7.4.1

前提

  • 2019/12/28 時点の情報
  • Amazon Linux 2 ( ami-068a6cefc24c301d2 )

amazon-linux-extras

Amazon Linux 2には amazon-linux-extras という便利コマンドがある。このコマンドを使うとサードパーティ製パッケージを割と新しめなバージョンでサクッとインストールできる。

aws.amazon.com

だがしかしbut、12/28時点ではPHP 7.4はサポートされておらず、フォーラムを見る限り予定も不明確。

Thread: amazon-linux-extras support for PHP 7.4

なので現時点でAmazon Linux 2でPHP 7.4を使うには、自分で頑張ってインストールする必要がある。

P.S.

この記事を書いた時点では入れられなかったが、2020/09/17 現在はamazon-linux-extrasでPHP 7.4を入れられるようになっている。今からPHP 7.4を入れるならそっちの方法が正攻法だと思われる。

ただし、この記事で紹介している方法は新バージョンのリリースからamazon-linux-extrasで使えるようになるまでラグの間は有用な方法ではあるので記事としては残しておく。

ざっくり手順

  1. EPELリポジトリを使えるようにする
  2. remiリポジトリを使えるようにする
  3. remiリポジトリを使って、PHP 7.4をインストールする

コマンドでいうとこちら

sudo amazon-linux-extras enable epel
sudo yum clean metadata
sudo yum install -y epel-release

sudo rpm -Uvh https://rpms.remirepo.net/enterprise/remi-release-7.rpm

sudo yum install --enablerepo remi -y php74

sudo ln -sf /usr/bin/php74 /usr/bin/php

一つづつ解説していく。

解説

1. EPELリポジトリを使えるようにする

fedoraproject.org

イカしたサードパーティ製ライブラリを提供するyumリポジトリ。有名な先進OS Fedoraのメンテナがメンテしてるので安心。

EPELはamazon-linux-extrasでインストール出来る。

$ sudo amazon-linux-extras enable epel
  0  ansible2                 available    [ =2.4.2  =2.4.6  =2.8 ]
  2  httpd_modules            available    [ =1.0 ]
  3  memcached1.5             available    \
        [ =1.5.1  =1.5.16  =1.5.17 ]
  5  postgresql9.6            available    [ =9.6.6  =9.6.8 ]
  6  postgresql10             available    [ =10 ]
  8  redis4.0                 available    [ =4.0.5  =4.0.10 ]
  9  R3.4                     available    [ =3.4.3 ]
 10  rust1                    available    \
        [ =1.22.1  =1.26.0  =1.26.1  =1.27.2  =1.31.0  =1.38.0 ]
 11  vim                      available    [ =8.0 ]
 13  ruby2.4                  available    [ =2.4.2  =2.4.4  =2.4.7 ]
 15  php7.2                   available    \
        [ =7.2.0  =7.2.4  =7.2.5  =7.2.8  =7.2.11  =7.2.13  =7.2.14
          =7.2.16  =7.2.17  =7.2.19  =7.2.21  =7.2.22  =7.2.23
          =7.2.24 ]
 16  php7.1                   available    \
        [ =7.1.22  =7.1.25  =7.1.27  =7.1.28  =7.1.30  =7.1.31
          =7.1.32  =7.1.33 ]
 17  lamp-mariadb10.2-php7.2  available    \
        [ =10.2.10_7.2.0  =10.2.10_7.2.4  =10.2.10_7.2.5
          =10.2.10_7.2.8  =10.2.10_7.2.11  =10.2.10_7.2.13
          =10.2.10_7.2.14  =10.2.10_7.2.16  =10.2.10_7.2.17
          =10.2.10_7.2.19  =10.2.10_7.2.21  =10.2.10_7.2.22
          =10.2.10_7.2.23  =10.2.10_7.2.24 ]
 18  libreoffice              available    [ =5.0.6.2_15  =5.3.6.1 ]
 19  gimp                     available    [ =2.8.22 ]
 20  docker=latest            enabled      \
        [ =17.12.1  =18.03.1  =18.06.1  =18.09.9 ]
 21  mate-desktop1.x          available    [ =1.19.0  =1.20.0 ]
 22  GraphicsMagick1.3        available    [ =1.3.29  =1.3.32 ]
 23  tomcat8.5                available    \
        [ =8.5.31  =8.5.32  =8.5.38  =8.5.40  =8.5.42 ]
 24  epel=latest              enabled      [ =7.11 ]
 25  testing                  available    [ =1.0 ]
 26  ecs                      available    [ =stable ]
 27  corretto8                available    \
        [ =1.8.0_192  =1.8.0_202  =1.8.0_212  =1.8.0_222  =1.8.0_232 ]
 28  firecracker              available    [ =0.11 ]
 29  golang1.11               available    \
        [ =1.11.3  =1.11.11  =1.11.13 ]
 30  squid4                   available    [ =4 ]
 31  php7.3                   available    \
        [ =7.3.2  =7.3.3  =7.3.4  =7.3.6  =7.3.8  =7.3.9  =7.3.10
          =7.3.11 ]
 32  lustre2.10               available    [ =2.10.5 ]
 33  java-openjdk11           available    [ =11 ]
 34  lynis                    available    [ =stable ]
 35  kernel-ng                available    [ =stable ]
 36  BCC                      available    [ =0.x ]
 37  mono                     available    [ =5.x ]
 38  nginx1                   available    [ =stable ]
 39  ruby2.6                  available    [ =2.6 ]
 40  mock                     available    [ =stable ]
 41  postgresql11             available    [ =11 ]

Now you can install:
 # yum clean metadata
 # yum install epel-release
$ sudo yum clean metadata
読み込んだプラグイン:extras_suggestions, langpacks, priorities, update-motd
リポジトリーを清掃しています: amzn2-core amzn2extra-docker amzn2extra-epel
10 個の metadata ファイルを削除しました
4 個の sqlite ファイルを削除しました
0 個の metadata ファイルを削除しました
$ sudo yum install -y epel-release
読み込んだプラグイン:extras_suggestions, langpacks, priorities, update-motd
amzn2-core                                                                                                      | 2.4 kB  00:00:00
amzn2extra-docker                                                                                               | 1.3 kB  00:00:00
amzn2extra-epel                                                                                                 | 1.3 kB  00:00:00
(1/5): amzn2-core/2/x86_64/group_gz                                                                             | 2.5 kB  00:00:00
(2/5): amzn2-core/2/x86_64/updateinfo                                                                           | 181 kB  00:00:00
(3/5): amzn2extra-epel/2/x86_64/primary_db                                                                      | 1.8 kB  00:00:00
(4/5): amzn2extra-docker/2/x86_64/primary_db                                                                    |  59 kB  00:00:00
(5/5): amzn2-core/2/x86_64/primary_db                                                                           |  36 MB  00:00:00
依存性の解決をしています
--> トランザクションの確認を実行しています。
---> パッケージ epel-release.noarch 0:7-11 を インストール
--> 依存性解決を終了しました。

依存性を解決しました

=======================================================================================================================================
 Package                           アーキテクチャー            バージョン                   リポジトリー                          容量
=======================================================================================================================================
インストール中:
 epel-release                      noarch                      7-11                         amzn2extra-epel                       15 k

トランザクションの要約
=======================================================================================================================================
インストール  1 パッケージ

総ダウンロード容量: 15 k
インストール容量: 24 k
Downloading packages:
epel-release-7-11.noarch.rpm                                                                                    |  15 kB  00:00:00
Running transaction check
Running transaction test
Transaction test succeeded
Running transaction
  インストール中          : epel-release-7-11.noarch                                                                               1/1
  検証中                  : epel-release-7-11.noarch                                                                               1/1

インストール:
  epel-release.noarch 0:7-11

完了しました!

2.remiリポジトリを使えるようにする

rpms.remirepo.net

remiもイカしたサードパーティ製ライブラリを提供するyumリポジトリ。

$ sudo rpm -Uvh https://rpms.remirepo.net/enterprise/remi-release-7.rpm
https://rpms.remirepo.net/enterprise/remi-release-7.rpm を取得中
警告: /var/tmp/rpm-tmp.cwom6N: ヘッダー V4 DSA/SHA1 Signature、鍵 ID 00f97f56: NOKEY
準備しています...              ################################# [100%]
更新中 / インストール中...
   1:remi-release-7.7-1.el7.remi      ################################# [100%]

3. PHP 7.4を入れる

あとはお目当てのものをインストールしていくだけ。

EPELもremiも、既存リポジトリと競合しないように無効化された状態でリポジトリ登録されているので、使うときはyumコマンドに --enablerepo remi のようにオプションを付けて明示的に有効化する必要がある。

$ sudo yum install --enablerepo remi -y php74
読み込んだプラグイン:extras_suggestions, langpacks, priorities, update-motd
(1/2): remi/primary_db                                                                                          | 2.6 MB  00:00:02
(2/2): remi-safe/primary_db                                                                                     | 1.7 MB  00:00:03
250 packages excluded due to repository priority protections
依存性の解決をしています
--> トランザクションの確認を実行しています。
---> パッケージ php74.x86_64 0:1.0-1.el7.remi を インストール

...

インストール:
  php74.x86_64 0:1.0-1.el7.remi

依存性関連をインストールしました:
  audit-libs-python.x86_64 0:2.8.1-3.amzn2.1                             checkpolicy.x86_64 0:2.5-6.amzn2
  environment-modules.x86_64 0:3.2.10-10.amzn2.0.2                       libX11.x86_64 0:1.6.5-2.amzn2.0.2
  libX11-common.noarch 0:1.6.5-2.amzn2.0.2                               libXau.x86_64 0:1.0.8-2.1.amzn2.0.2
  libcgroup.x86_64 0:0.41-21.amzn2                                       libselinux-python.x86_64 0:2.5-12.amzn2.0.2
  libsemanage-python.x86_64 0:2.5-11.amzn2                               libxcb.x86_64 0:1.12-1.amzn2.0.2
  ncurses-compat-libs.x86_64 0:6.0-8.20170212.amzn2.1.3                  php74-php-cli.x86_64 0:7.4.1-1.el7.remi
  php74-php-common.x86_64 0:7.4.1-1.el7.remi                             php74-php-json.x86_64 0:7.4.1-1.el7.remi
  php74-runtime.x86_64 0:1.0-1.el7.remi                                  policycoreutils-python.x86_64 0:2.5-22.amzn2
  python-IPy.noarch 0:0.75-6.amzn2.0.1                                   setools-libs.x86_64 0:3.3.8-2.amzn2.0.2
  tcl.x86_64 1:8.5.13-8.amzn2.0.2

完了しました!

php-mbstring などのPHP拡張を入れたいときは、 php74- というprefixをつける。 php-mbstring の場合は php74-php-mbstring 、といった具合。

$ sudo yum install --enablerepo remi -y php74-php-mbstring
読み込んだプラグイン:extras_suggestions, langpacks, priorities, update-motd
250 packages excluded due to repository priority protections
依存性の解決をしています
--> トランザクションの確認を実行しています。
---> パッケージ php74-php-mbstring.x86_64 0:7.4.1-1.el7.remi を インストール

...

インストール:
  php74-php-mbstring.x86_64 0:7.4.1-1.el7.remi

依存性関連をインストールしました:
  oniguruma5.x86_64 0:6.9.4-1.el7.remi

完了しました!

デフォルトでは php74 というコマンド名でインストールされる。symlinkを貼って php で呼べるようにしておくと便利。

$ php --version
-bash: php: コマンドが見つかりません

$ which php74
/usr/bin/php74

$ sudo ln -sf /usr/bin/php74 /usr/bin/php

$ php --version
PHP 7.4.1 (cli) (built: Dec 17 2019 16:35:58) ( NTS )
Copyright (c) The PHP Group
Zend Engine v3.4.0, Copyright (c) Zend Technologies

Happy PHP 7.4 Life!

PHPUnit 7系が2020年2月でサポート終了するぞ!バージョンアップを急げ!

PHPでデファクトスタンダードなテスティングツール PHPUnit の7系バージョンが2020年2月7日でサポートが終了します。

ざっくりまとめ

  • PHPUnit 7系(あるいはそれ以下)を使っているひとは、PHPUnit 8系へ乗り換えましょう
  • PHPUnit 8系はPHP7.2以上が必須。7.1以下の人は先にPHPのバージョンアップを計画しましょう

f:id:pinkumohikan:20191207174810p:plain
2020年2月でサポート終了

phpunit.de

github.com

PR

この記事は若手ものづくりコミュニティ Oysters のAdvent Calendar 2019にかこつけて書きました。

adventar.org

サポート終了するとどうなる?

PHPUnitはメジャーバージョンのリリースから2年がサポート期限で、既に4, 5, 6はサポート終了済み。現行は7系と8系で、7系はもうじきサポート終了です。

一般的にはサポートが切れるとそれ以降、改善がされなかったり、バグが修正されなかったり、ドキュメントが公式サイトから消去されて行ったり、脆弱性が見つかっても放置されたりします。

なので、サポート期限が来る前に新しいバージョンへ追従していくのが基本です。

え?そんな工数割けない?じゃあ最初からOSSなんて使わなければ良かったのに(真顔で火の玉ストレート攻撃ズドーン)

PHPUnit 7系から8系って何が変わる?

phpunit.de

大きなところでいうと

  • PHP 7.2が最低サポートバージョンになる
    • PHP 7.1以下の環境ではそもそもinstallできなくなる
  • ライフサイクル系メソッド (setUpとかtearDownとか) のreturn typeとして void が明示される
    • テストクラスでそれらを使っている場合、同じように void を明示しないとmethod signatureが合わないぞって怒られる
  • いくつかのアサーションメソッド、アノテーションがdeprecatedに
    • assertArraySubsetは個人的には好きだったのでちょっとショック

どんな流れでバージョンアップすれば良い?

だいたいいつもこんな感じで上げています。

  1. 手元でcomposer updateコマンドでPHPUnitをバージョンアップ
  2. 脳死でテストを走らせる
  3. 出てくるwarningやerrorをissueにまとめ、怒られのパターンを見る
  4. えいやで行けそうな数ならえいやで直す、そうでなければ怒られパターンごとに分割して直す
    • このとき現行バージョンでも動く変更を心がけ、バージョンアップのPRとは切り離して先行リリースしていくと変更の影響範囲を狭められてオススメです
  5. PHPUnitのバージョンアップをリリース (master等へmerge)

最後に

PHPUnitに限らず、OSSを使うならバージョンアップは割けて通れないと考えています。目先の工数削減のために脳死で使うんじゃなくて、OSS採用の際にはバージョンアップへの追従コストも考えましょう。また、バタバタしながらのビッグバン変更にならないよう、こまめに計画的にアップデートしていきましょう。

自分の前職では毎週、OSSのバージョンアップをやっていました。とても良い文化だなと思って自分の周りや今の職場でも普及活動中をしているところです。

techlog.voyagegroup.com

awscliで 'AWSHTTPSConnection' object has no attribute 'server_hostname' って怒られたときにやったこと

ざっくりまとめ

  • awscliをインストールして使おうとしたら何か怒られた
  • よく分からんけど、aptでインストールするのやめてpipで入れ直したら直った

起きたこと

とあるUbuntuサーバへawscliをインストールして、aws configureして、awsコマンドを叩いたところ下記のようなエラーが置きた

$ sudo apt install awscli
...

$ aws s3 ls
fatal error: 'AWSHTTPSConnection' object has no attribute 'server_hostname'

アイヤー、謎のエラー

エラーメッセージ的にはこっちの設定が悪いとかでは無さそうな雰囲気を感じる、良く分からんけど

やったこと

Try 1: 再インストール

エラーメッセージでぐぐったら、再インストールしたら直ったよ記事がいくつかヒットしたので試してみた

$ sudo apt remove awscli
...


$ sudo apt install awscli
...

$ aws s3 ls
fatal error: 'AWSHTTPSConnection' object has no attribute 'server_hostname'

ハイダメー!!!

Try 2: pipで入れ直す

何も考えずにaptでインストールしたけど、そう言えばいつもawscliはpipでインストールしていたのを思い出した

pipで入れ直してみる

$ sudo apt remove awscli
...

$ sudo pip3 install awscli
Traceback (most recent call last):
  File "/usr/bin/pip3", line 9, in <module>
    from pip import main
ImportError: cannot import name 'main'

あらやだ(たまに起こるけど、rootとしてログインしてからなら通るのでそれ以上調べる気にならずなんでこうなるのかちゃんと理解していない人の顔)

$ sudo --login pip3 install awscli
...
Successfully installed awscli-1.16.283

$ aws s3 ls
-bash: /usr/bin/aws: No such file or directory

チッ (aptで入れていたs3コマンドへのpathが通ったままなのでloginしなおす)

$ aws s3 ls
2019-11-16 18:23:14 very-nice-na-bucket

勝った

Laravelのレートリミットミドルウェアについて調べた

ざっくりまとめ

  • Laravelには任意のエンドポイントに対してレートリミットを行うためのミドルウェアが用意されている
  • 1分当たり10リクエストまで、という感じで制限可能
  • ログイン中ならユーザ、そうでなければIPアドレス単位でカウントされる

レートリミットとは

1分間に10回まで実行してよい、みたいな感じで制限を課すこと。Web APIや高負荷な集計/エクスポート機能といった、必要だがむやみに連打されたくない機能で利用することが多い

Laravelには、レートリミット機能を提供するミドルウェアが標準で用意されている

laravel.com

あんまりドキュメントには情報がないのでコードを追った

参考にしたコードは、Laravel 6.5リリース時点のもの

実装的にはこの辺から: https://github.com/laravel/framework/blob/v6.5.0/src/Illuminate/Routing/Middleware/ThrottleRequests.php

制限の単位

何分当たり何リクエストまで、という感じで指定可能

誰がどのぐらいリクエストしてきたかは内部的にはcacheで管理される

制限を超えると、ステータスコード429を返す

ユーザにこの画面を見せるわけにはいかないので、ちゃんと適切なエラーページを用意してあげよう

使い方

throttle:$何回まで,$何分間のうちに みたいな感じでミドルウェアを指定すれば使える

公式ドキュメントに乗っている下記の例だと、1分間に60回までリクエストを許すという設定になる

Route::middleware('auth:api', 'throttle:60,1')->group(function () {
    Route::get('/user', function () {
        //
    });
});

61回目のリクエストからは 429 Too Many Requests というエラーが表示される

f:id:pinkumohikan:20191113140120p:plain
429 Too Many Requests