mozjpeg3.1 を Amazon Linux用にフルビルドするメモ

 
ローカルのMac上で開発してると、一部のnpmモジュールはインストール時に自動でMac用のバイナリ生成のコードをインストールしてパスも通してくれちゃうので、そのまま同梱するとAWS Lambda上では当然動かない。
今回は画像の圧縮でよく使われる mozjpegpngquant がそれに当たった。
Lambdaをコールするたび、いちいちコンテナ上でインストールするのも微妙なので出来ればあらかじめ全部入りの実行ファイルをmakeしておく。
地味にいろいろ迷ったので作業メモする。
 
 
Amazon LinuxのDockerImageかubuntuのImage あたりをpullしてきて,docker-machine上で作業。
 

# 基本
apt-get update
apt-get install -y gcc make wget dpkg 

# mozjpeg用
apt-get install -y yasm nasm

wget https://github.com/mozilla/mozjpeg/releases/download/v3.1/mozjpeg-3.1-release-source.tar.gz
tar -xf mozjpeg-3.1-release-source.tar.gz
cd mozjpeg
./configure --disable-shared --enable-static 
make
make deb

 
ここ大事。 普通にやると多分実行時に symbol jpeg_float_quality_scaling, version LIBJPEG_6.2 not defined in file libjpeg.so.62 with link time reference とかで怒られる。

./configure --disable-shared --enable-static

 
これで可逆圧縮用の jpegtran や非可逆圧縮の cjpg が出来ている。
これらを同梱して既存のモジュールにエイリアス貼ったり愚直に置き換えるなりして Lambda上でも使える。
どうしてもLambda上で動いて欲しいものは1ファイルで実行できる形に持っていきたい。

Read More

nginx で特定のIPのみ別の upstream を使う

この記事はWanoグループ Advent Calendar 2016の17日目の記事…が書かれなかったので代理で埋められた記事です。

例えば、新しい機能をリリースするが、一度、関係者のみ本番リリースしたいようなとき。
現状の設定が以下のようになっているなら、

upstream backend_server {
  server 192.168.0.1:8000;
}

location / {
  proxy_pass http://backend_server;
}

次のように変更する。

upstream backend_server {
  server 192.168.0.1:8000;
}
# テスト用のアップストリーム を設定する
upstream backend_server_test {
  server 192.168.0.2:8000;
}
set $backend_server 'backend_server';
if ($http_remote_addr = '192.168.0.5') {
  set $backend_server 'bakcend_server_test';
}

location / {
  # proxy_pass には変数で渡す
  proxy_pass http://$backend_server;
}

このようにすると、REMOTE_ADDRが192.168.0.5の場合のみ、backend_server_test がバックエンドとして使われ、それ以外の場合は、今までと同様、backend_server が使われます。

nginx の設定は柔軟でいいですねー。

Read More

OpenSSHの設定ファイルを分割する

この記事はWanoグループ Advent Calendar 2016の15日目の記事です。

以前、.ssh/config を分割するという話を以前どこそこで見た時に、自分もやってみようと思って、やったやり方を紹介します。

僕の環境は、Ubuntu 16.04 なので、incron という時間ではなくて監視先のディレクトリ内のファイルの状態に応じて処理を実行できるものを利用します。
ちなみに、macOS には incron はないようです。監視して処理を実行する wait_on というコマンドはあるようですが、僕は Mac は使ってないので知りません。

まず、incron を使うためには、/etc/incron.allow にユーザー名を書く必要があるかもしれません(Ubuntu 16.04では必要でしたが、CentOS(少なくとも6系)だと多分不要)。

% cat /etc/incron.allow
ktat

実際のファイル分割のためのディレクトリ構成は以下のようにします。

 .ssh
    +- /configs/
    |   +- .base (共通の設定等をいれておく)
    |   +- host_groupA.config
    |   +- host_groupB.config
    |
    +- /backup/

incrontab -e で、以下のように登録します。

/home/ユーザー名/.ssh/configs/ IN_MODIFY,IN_CREATE,IN_DELETE,IN_MOVE /home/ユーザー名/bin/make_ssh_config $@ $#

これで、.ssh/configs/ の中のファイルが変更/作成/削除/移動されたら、即座に make_ssh_config コマンドが実行されます。
$@ は監視対象のパス(/home/ユーザー名/.ssh/configs/)に置き換わります。$#は実際に変わったファイル。
make_ssh_config は、監視対象のパスをコマンドに渡して、そこからの相対パスで処理しているので、.ssh/ の下の階層のディレクトリであれば、別にディレクトリ名は何でも良いです。

make_ssh_config は、以下です。

#!/bin/sh

target=$2

# emacs のバックアップファイルを無視
if [[ "$target" =~ "~$" ]]; then
    exit
fi

config_dir=$1
ssh_dir=$1..
log_file=$config_dir../backup/log.$(date +%Y-%m-%d-%H-%M-%S)

{
  set -e
  chmod 0600 $ssh_dir/config
  cp $ssh_dir/config $ssh_dir/backup/config.$(date +%Y-%m-%d-%H-%M)
  cat $config_dir/.base $config_dir/*.config > $ssh_dir/config.tmp
  mv $ssh_dir/config.tmp $ssh_dir/config
  chmod 0400 $ssh_dir/config
} 2>> $log_file

test -s $log_file || rm $log_file
find $config_dir../backup/ -type f -ctime +2 | xargs -r rm

やってることは、

  1. .ssh/config に書き込み権限を与える
  2. 元ファイルを backup ディレクトリにコピー
  3. ファイルを結合して、.ssh/config.tmp に書き込み
  4. .ssh/config に mv
  5. 書き込み権限を削る
  6. backup から2日以上たってるのを削除

incrontab の中にリダイレクトが書ければ、さくっと書いてしまうのですが、コマンドにしてしまった関係で多少色をつけることにしました。

これで、.ssh/configs/ 以下のファイルを編集したら、即座に .ssh/config が結合されます。権限も変更しているので間違って編集することもありません、という感じです。

Read More

シェルスクリプトの結果をメールに送ってみる

この記事はWanoグループ Advent Calendar 2016の8日目の記事です。

例えば、リリース用のコマンドなど、自作のシェルスクリプトを作ったとします。

その際に、実行中に出力された内容を他のみんなに共有したいなーと思ったとします。Slackに送るのにも使えますよ(うちは、特定のメールアドレスに送ったら、特定のチャンネルに届くようにしています)。まず、出力された内容をログファイルに書き込みましょう。


logfile=/path/to/log/$(date +%Y-%m-%d_%T).log

exec 1> >(tee $LOG_FILE)
exec 2>&1

こうるすることで、出力内容は、すべて /path/to/log/日付_時間.log 書き込まれます。

コマンドの引数や誰が実行したかを変数に入れておきます。


your_name=$(who am i | awk '{print $1}');
mailto="$your_name@example.com"
command_args="$@";

コマンドの実行中にプロンプトが出る場合は、それに対する応答も出力するようにしておきましょう。


echo -n "run? (y/n): "
read -p "" confirm;
echo "(select $confirm)" # ログに残すために echo しておく

次に _exit を定義して、exit を _exit に置換します。


function _exit () {
    n=$1;
    mark=""
    cat $log_file | sed -r "s/\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[m|K]//g" \
      | mail -s "[COMMAND_NAME] $command_args - $your_name" $mailto;
 }

途中でエラーが起きたり、Ctrl-Cで中断してもメールを送るようにしましょう。


set -o errexit
trap "echo;echo;echo 'COMMAND IS ABORTED!!';_exit 1" 1 2 3 15

既存のスクリプトに、これくらい追加することで、自作のスクリプトの実行結果をメールで送るようにできます。

最後に、サンプルのスクリプトを置いておきます。

#!/bin/bash

mailto='to@example.com';
log_file="/tmp/log.$(date +%Y-%m-%d).log";

exec 1> >(tee $log_file);
exec 2>&1;
 
set -o errexit
trap "echo; echo; echo 'COMMAND IS ABORTED!!'; _exit 1" 1 2 3 15;
 

your_name=$(who am i | awk '{print $1}');
command_args="$@";
is_success=1;
 
function main () {
    echo -e '\e[1;32mHello!\e[0m\n';
    echo "input 'OK' with enter.";
    read -p "" input;
    echo "(input: $input)";

    if [ "$input" = "OK" ]; then
        is_success=0;
        echo;
        echo "SUCCESS!";
    fi
    _exit $is_success;
}
 
function _exit () {
    n=$1;
    mark=""
    result="NG";
    if [ "$n" = "0" ]; then
        result="OK";
    fi
    trap "exit" 1 2 3 15;
    sed -r "s/\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[m|K]//g" $log_file \
      | mail -s "[COMMAND_NAME] $command_args - $result - $your_name $result" \
      $mailto;
}
main;

実行すると、以下のようなメールが届きます。

Hello!

input ‘OK’ with enter.
(input: OK)

SUCCESS!

Read More