Configuring and Running Redis 3.0.3 in Docker Container

# 概要

RedisのOFFICIAL REPOSITORYで公開されているRedis 3.0.3イメージをベースにしたRedisイメージを作成、実行するまでの手順です。

**環境**

下記の環境で動作確認を行いました。

* Windows7 (64bit)
* docker 1.8.1
 * redis 3.0.3

**参考**

下記のサイトを参考にさせて頂きました。

* [redis - OFFICIAL REPOSITORY] (https://hub.docker.com/_/redis/)
* [tokuhy/conf-jp] (https://github.com/tokuhy/conf-jp/blob/master/redis.2.8.x.conf)
* [net.core.somaxconnについて調べてみた] (http://tetsuyai.hatenablog.com/entry/20111220/1324466655)


## 事前準備

### redis.confの用意

```text:redis.conf
daemonize no
pidfile /var/run/redis.pid

port 6379
tcp-backlog 511

unixsocket /tmp/redis.sock
unixsocketperm 700

timeout 0
tcp-keepalive 0

loglevel notice
logfile /var/log/redis.log

databases 16

save 900 1
save 300 10
save 60 10000

stop-writes-on-bgsave-error yes

rdbcompression yes

rdbchecksum yes

dbfilename dump.rdb
dir /data

slave-serve-stale-data yes
slave-read-only yes

repl-diskless-sync no
repl-diskless-sync-delay 5
repl-disable-tcp-nodelay no

slave-priority 100

maxclients 100
maxmemory 10mb

appendonly yes
appendfilename "appendonly.aof"
appendfsync everysec

no-appendfsync-on-rewrite no

auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb

aof-load-truncated yes

lua-time-limit 5000

slowlog-log-slower-than 10000
slowlog-max-len 128

latency-monitor-threshold 0

notify-keyspace-events ""

hash-max-ziplist-entries 512
hash-max-ziplist-value 64
list-max-ziplist-entries 512
list-max-ziplist-value 64
set-max-intset-entries 512
zset-max-ziplist-entries 128
zset-max-ziplist-value 64
hll-sparse-max-bytes 3000

activerehashing yes

client-output-buffer-limit normal 0 0 0
client-output-buffer-limit slave 256mb 64mb 60
client-output-buffer-limit pubsub 32mb 8mb 60

hz 10

aof-rewrite-incremental-fsync yes
```

### Dockerfileの用意

```text:Dockerfile
FROM redis:3.0.3

# log file
RUN touch /var/log/redis.log && chmod 755 /var/log/redis.log && chown redis:redis /var/log/redis.log

# conf file
ADD redis.conf /tmp/redis.conf
RUN mkdir -p -m 755 /usr/local/etc/redis && chown redis:redis /usr/local/etc/redis && cp /tmp/redis.conf /usr/local/etc/redis && chown redis:redis /usr/local/etc/redis/redis.conf && rm /tmp/redis.conf

EXPOSE 6379

CMD ["redis-server","/usr/local/etc/redis/redis.conf"]
```

## イメージの作成

### redis 3.0.3イメージの取得

元になるredisのイメージを取得します。(一度だけ実行します。)

```bash:pull
$ docker pull redis:3.0.3
```

### ビルド

```bash:build
$ docker build -t rubytomato/redis303:0.1 .
```

ビルドしたイメージからコンテナを作成し実行します。
データを永続化するため、AOFファイルおよびRDBファイルが配置される/dataディレクトリをホストの共有ディレクトリにマッピングします。

```bash:run
$ docker run -d --name my-redis -p 6379:6379 -v /c/Users/Username/dev/docker/redis3.0.3:/data rubytomato/redis303:0.1
```

* 共有ディレクトリのパスの一部をマスクしています。

```bash:ps
$ docker ps --format="{{.ID}}\\t{{.Status}}\\t{{.Ports}}\\t{{.Names}}"
fd95ba3b2322    Up 48 seconds   0.0.0.0:6379->6379/tcp  my-redis
```

念のためredis.logを確認します。

```bash:exec
$ docker exec -it my-redis bash

root@fd95ba3b2322:~# cat /var/log/redis.log
                _._
           _.-``__ ''-._
      _.-``    `.  `_.  ''-._           Redis 3.0.3 (00000000/0) 64 bit
  .-`` .-```.  ```\/    _.,_ ''-._
 (    '      ,       .-`  | `,    )     Running in standalone mode
 |`-._`-...-` __...-.``-._|'` _.-'|     Port: 6379
 |    `-._   `._    /     _.-'    |     PID: 1
  `-._    `-._  `-./  _.-'    _.-'
 |`-._`-._    `-.__.-'    _.-'_.-'|
 |    `-._`-._        _.-'_.-'    |           http://redis.io
  `-._    `-._`-.__.-'_.-'    _.-'
 |`-._`-._    `-.__.-'    _.-'_.-'|
 |    `-._`-._        _.-'_.-'    |
  `-._    `-._`-.__.-'_.-'    _.-'
      `-._    `-.__.-'    _.-'
          `-._        _.-'
              `-.__.-'

1:M 24 Aug 18:26:08.808 # Server started, Redis version 3.0.3
1:M 24 Aug 18:26:08.809 # 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.
1:M 24 Aug 18:26:08.809 # WARNING you have Transparent Huge Pages (THP) support enabled in your kernel. This will create latency and memory usage issues with Redis. To fix this issue run the command 'echo never > /sys/kernel/mm/transparent_hugepage/enabled' as root, and add it to your /etc/rc.local in order to retain the setting after a reboot. Redis must be restarted after THP is disabled.
1:M 24 Aug 18:26:08.809 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.
1:M 24 Aug 18:26:08.809 * The server is now ready to accept connections on port 6379
1:M 24 Aug 18:26:08.809 * The server is now ready to accept connections at /tmp/redis.sock
```

Warningが3件表示されていますが、原因と対策は[Redis と php-pecl-redis のインストールメモ（CentOS7.1.1503）] (https://blog.apar.jp/linux/2959/)というサイトで詳しく説明されています。
ただベースとなるDebianにはsysctlが無いようで対応の仕方がわかりませんでした。


#### コンテナの実行に失敗する場合

コンテナの実行で失敗する場合はログに原因が出力されていないか確認します。
例えば、このような情報が得られます。

```bash:logs
$ docker logs fd95ba3b2322

*** FATAL CONFIG FILE ERROR ***
Reading the configuration file, at line 940
>>> 'aof-rewrite-incremental-fsyn'
Bad directive or wrong number of arguments
```


#### redis-cli

redis-cliコンテナを実行します。

```bash:redis-cli
$ docker run -it --link my-redis:redis --rm rubytomato/redis303:0.1 sh -c 'exec redis-cli -h "$REDIS_PORT_6379_TCP_ADDR" -p "$REDIS_PORT_6379_TCP_PORT"'
172.17.0.3:6379>
```

**redis-cliを実行する別の方法**

execコマンドでコンテナに入り直接redis-cliを実行します。

```bash:exec
$ docker exec -it my-redis bash
```

```shell-session
# redis-cli
172.17.0.3:6379>
```

**テストデータを一括で作成する**

下記のスクリプトを`test_data.sh`というファイルで保存して実行します。
`key:xxx`という名前のキーが1000件作成されます。

```shell-session:test_data.sh
#!/bin/bash

for a in {1..1000}
do
redis-cli set key:$a $a
done
```

この内容は[シェルスクリプトでredisデータ作成] (http://qiita.com/shell/items/4d3fca4b27fb674b173a)を参考にさせて頂きました。



## メモ

redisのログに出力されている3つのWARNINGの対処方法のメモです。
仮想マシン(ホスト)側の設定を変えることで対処できる部分がありました。またこの変更を永続化するためにVirtualboxでスナップショットを取る必要があります。

### overcommit_memory

```text
WARNING overcommit_memory is set to 0! Background save may fail under low memory condition.
```

ホスト側のsysctl.confを下記のように編集し、編集後に`sudo sysctl -p`で反映します。

`/etc/sysctl.conf`に下記の行を追加

```text:sysctl.conf
vm.overcommit_memory = 1
```


### Disable Transparent Huge Pages

```text
WARNING you have Transparent Huge Pages (THP) support enabled in your kernel.
```

現在値の確認

```bash
$ sudo cat /sys/kernel/mm/transparent_hugepage/enabled
[always] madvise never
$ sudo cat /sys/kernel/mm/transparent_hugepage/defrag
[always] madvise never
```

ホスト側でrootアカウントにスイッチして下記の操作を行います。

```bash
$ sudo su
```

```shell-session
# echo never > /sys/kernel/mm/transparent_hugepage/enabled
# echo never > /sys/kernel/mm/transparent_hugepage/defrag
```

変更後の確認

```shell-session
# cat /sys/kernel/mm/transparent_hugepage/enabled
always madvise [never]
# cat /sys/kernel/mm/transparent_hugepage/defrag
always madvise [never]
```


### somaxconn

:exclamation: このワーニングは下記の方法では解決できませんでした。

```text
WARNING: The TCP backlog setting of 511 cannot be enforced ...
```

ホスト側のsysctl.confを下記のように編集し、編集後に`sudo sysctl -p`で反映します。

`/etc/sysctl.conf`に下記の行を追加

```text:sysctl.conf
net.core.somaxconn = 1024
```

正しい対処方法かはわかりませんが、redis.confの`tcp_backlog`の値を128に下げることでワーニングを消すことはできます。