Edited at

Redisのインストール・セットアップ

More than 3 years have passed since last update.

Redis 冗長化 & フェールオーバー環境を CentOS 6.x 上に構築する手順です

手順は3部構成となっており、本稿は Redis のインストール方法となります

 (その1):Redisのインストール

 (その2):Redisの冗長化

 (その3):Redis-Sentinelによるフェールオーバー環境の構築


環境

・CentOS release 6.x

・Redis 3.0.7

・Redis-Sentinel 3.0.7


構成の概要

まずは以下構成で Redis を構築します

起動ファイル
ポート
設定ファイル
説明

redis
6379
6379.conf
Redis 本体です


Redis のインストール

パッケージから導入する方法と、ソースからインストールする2種類の方法があります

各自の環境制約を踏まえて導入手段を検討してください


パッケージから導入する場合

Redis は標準パッケージに含まれていません(2015/11/15時点)

サードパーティのリポジトリをインストールするので、標準リポジトリしか利用できない環境では後述の「ソースからインストール」にスキップしてください

サードパーティのリポジトリをセットアップします

remi と EPEL リポジトリが必要です導入手順はこちら

メモリ管理に tcmalloc を利用しているため gperftools-libs もインストールします


CentOS5/6

$ sudo yum install --enablerepo=epel gperftools

$ yum info --enablerepo=remi redis | egrep "Version|バージョン"
Version : 3.0.7
$ sudo yum install --enablerepo=remi redis

自動起動スクリプトがインストールされるので、実行して正常起動することを確認します


Redisサーバ起動

$ sudo service redis start

redis-server を起動中: [ OK ]


プロセス確認

$ ps -ef | grep redis

redis 10995 1 0 21:57 ? 00:00:00 /usr/bin/redis-server 127.0.0.1:6379

Redis に接続してバージョンを確認します


接続確認

$ redis-cli info | grep redis_version

redis_version:3.0.7


Redis のワークディレクトリ作成

パッケージ版では設定ファイルの配置先が /etc/ 直下となります

Redis 冗長化にあたり設定ファイルは複数作成するので、煩雑回避のため Redis 用のワークディレクトリを作成して集約させます

なお redis ユーザが書き込めるよう権限を付与しておきます

 /etc/redis:設定ファイルの格納先


Redisワークディレクトリの作成

$ sudo mkdir /etc/redis

$ sudo chmod 755 /etc/redis
$ sudo chown redis:redis /etc/redis


自動起動スクリプトの修正

設定ファイルの配置先を変更したので REDIS_CONFIG を変更します

複数プロセス立ち上げるので pidfile もポート番号を付加しておきます


/etc/init.d/redis

$ sudo vi /etc/init.d/redis


#pidfile="/var/run/redis/redis.pid"
#REDIS_CONFIG="/etc/redis.conf"
REDISPORT=6379
pidfile="/var/run/redis/redis_${REDISPORT}.pid"
REDIS_CONFIG="/etc/redis/${REDISPORT}.conf"


Redis 設定ファイルのコピー

ポートごとの設定ファイルにするので元の設定ファイルをコピーします


Redis設定ファイル雛形のコピー

$ sudo cp -p /etc/redis.conf /etc/redis/6379.conf


ここまで実施したら「Redis 設定ファイルの編集」までスキップしてください


ソースからインストールする場合

Redis のホームページからソースをダウンロードしてインストールします

2016/2/3時点の最新版は、3.0.7 のようです

Redis の冗長構成には redis 2.4.16 または 2.6.0-rc6 以降のバージョンが必要です

こちらで適切なバージョンを確認して、以下コマンドのファイル名を変更してください

Downlod 一覧


redisのソースダウンロード

$ cd

$ cd Downlods
$ wget http://download.redis.io/releases/redis-3.0.7.tar.gz


redisのインストール

$ tar xzf redis-3.0.*.tar.gz

$ cd redis-3.0.*
$ make
$ sudo make install

make でエラーが発生する場合は、開発ツールをインストールしてください

make[3]: gcc: コマンドが見つかりませんでした

make[3]: *** [net.o] エラー 127

$ sudo yum groupinstall 'Development Tools'

デフォルトのインストール先は、/usr/local/bin/ です

変更したい場合は、redis-3.0.*/src の配下の Makefile を手動で変更します


Makefile

PREFIX?=インストール先ディレクトリ名



Redis ユーザ及びグループの作成

Redis インスタンスを起動するユーザとグループを作成します

ログインは不要なので nologin を指定します

$ sudo groupadd redis

$ sudo useradd -s /sbin/nologin -M -g redis redis


Redis のワークディレクトリ作成

Redis 用のワークディレクトリを作成し、 redis ユーザの書き込み権限を付与します

必要なワークディレクトリは以下となります

 /etc/redis:設定ファイルの格納先

 /var/run/redis:データファイルや起動プロセスIDファイルの格納先

 /var/log/redis:ログ出力先


Redisワークディレクトリの作成

$ sudo mkdir /etc/redis /var/run/redis /var/log/redis

$ sudo chmod 755 /etc/redis /var/run/redis /var/log/redis
$ sudo chown redis:redis /etc/redis /var/run/redis /var/log/redis


Redis 設定ファイルのコピー

ソースインストールでは Redis 設定ファイルの雛形が用意されているので格納先ディレクトリにコピーします

パッケージ導入では既に配置されています。この章はスキップしてください


Redis設定ファイル雛形のコピー

$ sudo cp -p ~/Downloads/redis-3.0.*/redis.conf /etc/redis/6379.conf



Redis サーバの起動と停止

Redis 起動シェルスクリプトを引数に設定ファイルを指定し redis ユーザで起動します


redisの起動

$ sudo -u redis sh -c "redis-server /etc/redis/6379.conf --daemonize yes --dir /var/run/redis"


Redis が正常に起動すれば以下のメッセージが画面に出力されます

6251:M 03 Feb 04:46:23.166 # You requested maxclients of 10000 requiring at least 10032 max file descriptors.

6251:M 03 Feb 04:46:23.166 # Redis can't set maximum open files to 10032 because of OS error: Operation not permitted.
6251:M 03 Feb 04:46:23.166 # Current maximum open files is 4096. maxclients has been reduced to 4064 to compensate for low ulimit. If you need higher maxclients increase 'ulimit -n'.
_._
_.-``__ ''-._
_.-`` `. `_. ''-._ Redis 3.0.7 (00000000/0) 64 bit
.-`` .-```. ```\/ _.,_ ''-._
( ' , .-` | `, ) Running in standalone mode
|`-._`-...-` __...-.``-._|'` _.-'| Port: 6379
| `-._ `._ / _.-' | PID: 6251
`-._ `-._ `-./ _.-' _.-'
|`-._`-._ `-.__.-' _.-'_.-'|
| `-._`-._ _.-'_.-' | http://redis.io
`-._ `-._`-.__.-'_.-' _.-'
|`-._`-._ `-.__.-' _.-'_.-'|
| `-._`-._ _.-'_.-' |
`-._ `-._`-.__.-'_.-' _.-'
`-._ `-.__.-' _.-'
`-._ _.-'
`-.__.-'

別のターミナルを立ち上げて Redis クライアントから接続してみます

重要:

 初期状態では Redis はサービスとして起動していないので、プロンプトは戻ってきません

 よって別のターミナルを立ち上げて操作する必要があります


Redis接続

$ redis-cli -p 6379


Redisサーバから PING コマンドで PONG が返却されることを確認します

127.0.0.1:6379> ping

PONG

接続確認ができたら Redis サーバを終了させます

切断後は PING コマンドで PONG が返却されないことを確認してください

 重要

 デフォルトの設定では データファイル書き出し先に権限に無いため shutdown コマンドで単純に終了できません

 必ず、config set コマンドで dir を指定してから shutdown してください

 これは後ほど、設定ファイルで デーモン化 することで対処します


Redisサーバの終了

127.0.0.1:6379> config set dir /var/run/redis

127.0.0.1:6379> shutdown
not connected>
not connected> ping
Could not connect to Redis at 127.0.0.1:6379: Connection refused
not connected> exit

ps コマンドでも redis プロセスが出力されないことを確認しましょう

$ ps -e | grep redis

★ 何も表示されないこと


自動起動スクリプトのコピー

ソースからインストールした場合は、自動起動のスクリプトを設定する必要があります

サーバの再起動でも自動で Redis を起動させるため、用意された自動起動スクリプトをコピーして登録します


自動起動スクリプトのコピー

$ sudo cp -p ~/Downloads/redis-3.0.*/utils/redis_init_script /etc/init.d/redis


自動起動スクリプトを修正します

ヘッダの5行目に chkconfig: 345 70 15 を追記します(下記の最終行です)

プロセスIDファイルの配置場所も変更します

もしパスワードを設定する場合は、CLIEXEC も変更しておきます

 重要

  Redisでは、接続時にセキュリティを高めるためパスワード設定ができます

  もしパスワードを設定したら起動スクリプトでもセットが必要です

  これをやらないと Redisサーバプロセスを スクリプトから終了させることができません...

  対応としては CLIEXEC に -a の引数でパスワードを指定します


/etc/init.d/redis

$ sudo vi /etc/init.d/redis

#!/bin/sh
#
# Simple Redis init.d script conceived to work on Linux systems
# as it does use of the /proc filesystem.
# chkconfig: 345 70 15

#CLIEXEC=/usr/local/bin/redis-cli ★ ここはパスワード設定した場合のみ変更します!!
CLIEXEC="/usr/local/bin/redis-cli -a hoge"
#PIDFILE=/var/run/redis_${REDISPORT}.pid
PIDFILE=/var/run/redis/redis_${REDISPORT}.pid


Redis 設定ファイルの編集

ここからはパッケージ導入でもソース導入でも必要な作業となります

Redis サーバの環境設定をおこないます


Redis設定ファイルの編集

$ sudo vi /etc/redis/6379.conf



6379.conf

daemonize yes

pidfile redis_6379.pid
port 6379
bind 127.0.0.1
loglevel notice
logfile /var/log/redis/6379.log
dbfilename 6379.rdb
dir /var/run/redis
requirepass hoge
maxclients 1024

各項目の詳細は以下となります

 1. daemonize:Redisをデーモンで起動させます

 2. pidfile:Redisのプロセスファイルの名前を指定します(ポート番号にあわせてます)

 3. port:起動するポート番号を指定します

 4. bind:接続可能なサーバのIPアドレスを指定します

  重要

   コメントアウトまたは'0.0.0.0'で制限解除となります

   ただしセキュリティの確保のためにも接続するサーバのみへ制限しておきましょう

   本稿では同一サーバから接続するので 127.0.0.1 としています

   なお複数のサーバから接続する場合は、スペース区切りでIPアドレスを列挙します

   あわせて iptables で接続するサーバのIPとポートを解放する必要があります

 5. ログ出力レベルを指定します

  検証中は debug または info 、サービス稼働では notice としておきましょう

 6. ログファイルの名前を指定します(ポート番号にあわせてます)

 7. RDB(永続性担保のスナップショット)のファイル名を指定します(ポート番号にあわせてます)

   Redisの魅力としてデータの永続性担保が挙げられます

   メモリ内のデータをあるタイミングでファイルに書き出します

 8. redis実行時のベースディレクトリを指定します

 9. パスワードを指定します

  重要

   サンプルとして hoge としてますが、わかりにくい適切なパスワードに変更してください

 10. 接続できる最大コネクション数を指定します

  重要

   複数のHTTPサーバから利用する場合は、サーバ台数 × MaxClient などの考慮が必要です

   場合によっては最大接続数がデフォルトの 1024 では足りないケースもあります

   ただTCP接続ではファイルディスクリプタが利用されるため、OSのファイルオープン数の

   制限値を考慮する必要があり、単純に設定値を拡張できません

   1024 で足りない場合は後述の Redis 自動起動ファイル内でlimit制限を変更します


Redisの起動設定

Redisサーバの設定後、起動スクリプトで Redis サーバの起動と停止ができることを確認します


Redisサーバの起動

$ sudo /etc/init.d/redis start

Starting Redis server...
$ ps -ef | grep redis
root 3328 1 0 05:27 ? 00:00:00 /usr/local/bin/redis-server 127.0.0.1:6379

Redisに接続します

設定ファイルの requirepass で指定したパスワードを auth コマンドで入力し認証をとおしてから PING コマンドで PONG が返却されることを確認します

$ redis-cli -p 6379

127.0.0.1:6379> auth hoge
OK
127.0.0.1:6379> ping
PONG
127.0.0.1:6379> quit

自動起動スクリプトで終了できることを確認します


Redisサーバの停止

$ sudo /etc/init.d/redis stop

Stopping ...
Redis stopped
$ ps -e | grep redis
$ /usr/local/bin/redis-cli -p 6379
Could not connect to Redis at 127.0.0.1:6379: Connection refused

Redisの起動と終了は、以下コマンドでもOKです

$ sudo service redis start

$ sudo service redis restart
$ sudo service redis stop


redis の自動起動(サービス)登録

起動スクリプトで正常に起動と終了ができることを確認してからサービスとして登録します

$ sudo chkconfig redis on

$ chkconfig --list redis
redis 0:off 1:off 2:on 3:on 4:on 5:on 6:off

サーバを再起動させて Redis が自動起動されることを確認します


サーバ再起動

$ reboot


サーバが再起動したら


Redis自動起動の確認

$ ps -ef | grep redis

redis 2042 1 0 06:26 ? 00:00:00 /usr/bin/redis-server 127.0.0.1:6379


Redis の冗長化

複数の Redis でレプリケートさせる方法はRedisのフェールオーバー環境を構築する(その2)で説明します


Appendix


iptablesの変更

外部のサーバから Redis に接続する場合は、iptables の設定が必要です。

IPアドレス(帯域指定可)と redis のポートを許可し、iptables サービスを再起動させて反映します


iptables

$ sudo vi /etc/sysconfig/iptables

-A INPUT -p tcp -m tcp -s 128.0.0.0/24 --dport 6379 -j ACCEPT


iptablesの再起動

$ sudo /etc/init.d/iptables restart



メモリオーバーコミットの設定

redis の起動時に以下メッセージがログに表示される場合があります


/var/log/redis/redis.log

# WARNING overcommit_memory is set to 0! Background save may fail under low memory condition. To fix this issue add 'vm.overcommit_memory = 1' to /etc/sysctl.conf and then reboot or run the command 'sysctl vm.overcommit_memory=1' for this to take effect.

[15050] 16 Jan 22:17:28.303 * DB loaded from disk: 0.000 seconds

Linux では実メモリが足りなくなり、溢れたスワップ領域も使い切ってしまうとメモリを

確保しているプロセスを強制終了させる仕組みがあります(OOMKillerと呼ばれてます)

0:空き容量がなければ実行中のプロセスを強制終了する(デフォルト)

1:制限ギリギリまでメモリがあるように振る舞い、確保できなければ実行中のプロセスを強制終了する
2:空き容量がない場合はエラーを発生させる

redis はデータ永続化(スナップショットやAOFログ保存)の際、格納データの2倍のメモリを利用するので

もしメモリを使い切ってしまい、確保(allocate)に失敗した場合は エラーが発生します

この時、OOMKiller の設定によっては redis プロセスが強制終了されます

ワーニングメッセージでは vm.overcommit_memory = 1 をセットと表示されていますが

本来ならエラーを誘発させアプリ側でエラートラップすべきなので、"2"をセットします

(ここ解釈を間違えてるかもしれません。詳しい方教えてくださいませ)

なおシステム設定ファイルはバックアップを取ってから変更します

また変更後はサーバの再起動が必要です

$ sudo cp -p /etc/sysctl.conf /etc/sysctl.conf_`date '+%Y%m%d'`

$ sudo vi /etc/sysctl.conf
vm.overcommit_memory = 2

$ sudo shutdown -r now


crackit/crack@redis.io

redis コマンドの “config set dbfilename” 機能を悪用した、redis 起動ユーザ権限で任意のファイルが作成できる攻撃手法が公開されています。

(= sshの公開鍵を配置してリモートログイン用の穴を開けてしまう)

redis著者による攻撃考察はこちら

原因は bind の設定忘れで、もし攻撃を受けると、crackit というキーと、バリューに sshキーとcrack@redis.io が登録されます。(見ればすぐヤバイと感じます)

他サーバとの接続検証などで、bind設定(IPアドレス制限)を解放した場合、その後閉じることを忘れずに実施することが重要です

対処方法は

1. redis.conf の bind でIPを制限する(閉じる)

 接続できるサーバのIPアドレスを指定し、redisを再起動する

$ sudo vi /etc/redis/redis.conf

bind 127.0.0.1
$ sudo /etc/init.d/redis restart


  1. iptables でredisのポートを閉じる

    redisのポートにアクセスできるIPアドレスのみ指定し、iptabelsを再起動する


$ sudo vi /etc/sysconfig/iptables

 [IP帯域で許可する場合]
 -A INPUT -p tcp -m tcp -s [接続させるIP帯域] –dport 6379 -j ACCEPT

 [ポート閉塞する場合]
  6397の行をコメントアウト(もしくは6379関連は記載しない)

$ sudo /etc/init.d/iptables restart

以上です