前言
Redis 是C语言编写的开源内存型KV存储Tip: The name Redis means REmote DIctionary Server目前互联网应用中大量使用着 Redis
Docker 又是 DevOps 神器
两者结合使用可以给开发带来极大便利
但是目前来讲,容器更适合运行无状态的服务,因为这样可以更方便地进行水平扩展,而存储一类属于典型的有状态应用,所以处理起来要有更多注意
主要得注意以下三方面:
- 配置 : 使用默认配置有时满足不了客制化需求
- 数据 : 做缓存时可以不用关心,如果开启持久化,显然不便于放在镜像中
- 日志 : 默认情况下日志会写到标准输出,然后由Docker log 收集,但有时这不便于日志管理(也只是有了Docker后才大量使用这种处理方式,对于现有的日志收集系统侵入性比较强),应该写到一个指定位置,便于后期处理和分析
Tip: 其实还有网络,由于Redis异步非阻塞的事件驱动特性,接受处理网络请求非常快,这时docker的转发网络就变成了性能瓶颈(系统内核会多把一层关),直接使用主机网络可以有效缓解这个问题,但这里用于开发环境,暂时不用考虑这里分享一下 Redis 容器的相关操作和基础,详细可以参考 Docker Hub 和 官方文档
Tip: 当前的最新版本为 Redis 3.0.7
概要
环境
[root@h104 ~]# hostnamectl
Static hostname: h104
Icon name: computer-vm
Chassis: vm
Machine ID: 12a02f8ee88d4b8e91d54d1390b0b275
Boot ID: 6109315d5e854747b7732bb2d163ed34
Virtualization: vmware
Operating System: CentOS Linux 7 (Core)
CPE OS Name: cpe:/o:centos:centos:7
Kernel: Linux 3.10.0-327.4.4.el7.x86_64
Architecture: x86-64
[root@h104 ~]# uname -a
Linux h104 3.10.0-327.4.4.el7.x86_64 #1 SMP Tue Jan 5 16:07:00 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux
[root@h104 ~]# docker --version
Docker version 1.9.1, build a34a1d5
[root@h104 ~]#
启动一个redis容器
由于本地并没有 redis 镜像,所以它会自动去 dockerhub 上拉取[root@h104 ~]# docker run --name test-redis -d redis
Unable to find image 'redis:latest' locally
latest: Pulling from library/redis
70e9a6907f10: Pull complete
32f2a4cccab8: Pull complete
34446d9c0a72: Pull complete
145623ef4dd4: Pull complete
8d9771e0b6ee: Pull complete
018a9e995b7a: Pull complete
0deb375d521a: Pull complete
c152ff671a13: Pull complete
aa64b511d09c: Pull complete
23c6ea3916be: Pull complete
9cd603438a28: Pull complete
8be59f114d61: Pull complete
70aeeb507933: Pull complete
840927008ad0: Pull complete
970117e3ce7f: Pull complete
9d6240c55f04: Pull complete
b2f46bd01929: Pull complete
1f4ff6e27d64: Pull complete
Digest: sha256:68524efa50a33d595d7484de3939a476b38667c7b4789f193761899ca125d016
Status: Downloaded newer image for redis:latest
71c69b5bf62cc4521a43f91869114d598eab5d4826372371909c461e6f024f71
[root@h104 ~]#
[root@h104 ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
71c69b5bf62c redis "docker-entrypoint.sh" 49 seconds ago Up 48 seconds 6379/tcp test-reds
[root@h104 ~]#
[root@h104 ~]# docker logs 71c69b5bf62c
1:C 28 Apr 02:41:05.459 # Warning: no config file specified, using the default config. In order to specify a config file use redis-sever /path/to/redis.conf
_._
_.-``__ ''-._
_.-`` `. `_. ''-._ Redis 3.0.7 (00000000/0) 64 bit
.-`` .-```. ```\/ _.,_ ''-._
( ' , .-` | `, ) Running in standalone mode
|`-._`-...-` __...-.``-._|'` _.-'| Port: 6379
| `-._ `._ / _.-' | PID: 1
`-._ `-._ `-./ _.-' _.-'
|`-._`-._ `-.__.-' _.-'_.-'|
| `-._`-._ _.-'_.-' | http://redis.io
`-._ `-._`-.__.-'_.-' _.-'
|`-._`-._ `-.__.-' _.-'_.-'|
| `-._`-._ _.-'_.-' |
`-._ `-._`-.__.-'_.-' _.-'
`-._ `-.__.-' _.-'
`-._ _.-'
`-.__.-'
1:M 28 Apr 02:41:05.461 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to te lower value of 128.
1:M 28 Apr 02:41:05.461 # Server started, Redis version 3.0.7
1:M 28 Apr 02:41:05.461 # WARNING overcommit_memory is set to 0! Background save may fail under low memory condition. To fix this isse add 'vm.overcommit_memory = 1' to /etc/sysctl.conf and then reboot or run the command 'sysctl vm.overcommit_memory=1' for this to tke effect.
1:M 28 Apr 02:41:05.461 # WARNING you have Transparent Huge Pages (THP) support enabled in your kernel. This will create latency and emory usage issues with Redis. To fix this issue run the command 'echo never > /sys/kernel/mm/transparent_hugepage/enabled' as root, nd 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 28 Apr 02:41:05.461 * The server is now ready to accept connections on port 6379
[root@h104 ~]# sysctl -a | grep vm.overcommit_memory
vm.overcommit_memory = 0
[root@h104 ~]# cat /sys/kernel/mm/transparent_hugepage/enabled
[always] madvise never
[root@h104 ~]#
[root@h104 ~]# docker images | grep redis
redis latest 1f4ff6e27d64 6 days ago 177.4 MB
[root@h104 ~]#
这种状态下的redis在后台运行,没有公开端口可以让外面的客户端直连
但是可以通过link的方式,实现容器间的对接
使用客户端容器连接
[root@h104 ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
71c69b5bf62c redis "docker-entrypoint.sh" 6 hours ago Up 7 minutes 6379/tcp test-redis
[root@h104 ~]# docker run -it --link test-redis:redis --rm redis redis-cli -h redis -p 6379
redis:6379> info
# Server
redis_version:3.0.7
redis_git_sha1:00000000
redis_git_dirty:0
redis_build_id:6f8b503a2787e3a6
redis_mode:standalone
os:Linux 3.10.0-327.4.4.el7.x86_64 x86_64
arch_bits:64
multiplexing_api:epoll
gcc_version:4.9.2
process_id:1
run_id:9515a58ed6b97720e31a6a7ecafa4d8f7dbde630
tcp_port:6379
uptime_in_seconds:584
uptime_in_days:0
hz:10
lru_clock:2216150
config_file:
# Clients
connected_clients:1
client_longest_output_list:0
client_biggest_input_buf:0
blocked_clients:0
# Memory
used_memory:815912
used_memory_human:796.79K
used_memory_rss:7909376
used_memory_peak:815912
used_memory_peak_human:796.79K
used_memory_lua:36864
mem_fragmentation_ratio:9.69
mem_allocator:jemalloc-3.6.0
# Persistence
loading:0
rdb_changes_since_last_save:0
rdb_bgsave_in_progress:0
rdb_last_save_time:1461833358
rdb_last_bgsave_status:ok
rdb_last_bgsave_time_sec:-1
rdb_current_bgsave_time_sec:-1
aof_enabled:0
aof_rewrite_in_progress:0
aof_rewrite_scheduled:0
aof_last_rewrite_time_sec:-1
aof_current_rewrite_time_sec:-1
aof_last_bgrewrite_status:ok
aof_last_write_status:ok
# Stats
total_connections_received:1
total_commands_processed:0
instantaneous_ops_per_sec:0
total_net_input_bytes:14
total_net_output_bytes:0
instantaneous_input_kbps:0.00
instantaneous_output_kbps:0.00
rejected_connections:0
sync_full:0
sync_partial_ok:0
sync_partial_err:0
expired_keys:0
evicted_keys:0
keyspace_hits:0
keyspace_misses:0
pubsub_channels:0
pubsub_patterns:0
latest_fork_usec:0
migrate_cached_sockets:0
# Replication
role:master
connected_slaves:0
master_repl_offset:0
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0
# CPU
used_cpu_sys:2.94
used_cpu_user:0.16
used_cpu_sys_children:0.01
used_cpu_user_children:0.00
# Cluster
cluster_enabled:0
# Keyspace
redis:6379>
redis:6379>
redis:6379>
redis:6379> CONFIG get *data*
1) "databases"
2) "16"
3) "slave-serve-stale-data"
4) "yes"
redis:6379> exit
[root@h104 ~]#
[root@h104 ~]# docker ps -a | grep redis
71c69b5bf62c redis "docker-entrypoint.sh" 6 hours ago Up 31 minutes 6379/tcp test-redis
[root@h104 ~]#
docker run -it --link test-redis:redis --rm redis redis-cli -h redis -p 6379
进行一下解析Option | Comment |
---|---|
docker run |
调用 docker 命令的 run 子命令 |
-i |
打开 STDIN ,进入交互模式 |
-t |
分配一个伪终端,一般都和 -i 一起使用 |
--link test-redis:redis |
连接 test-redis 容器,并且为这个容器定义一个别名,叫 redis (redis-cli -h redis -p 6379 中指定的 redis 就是用的这个别名) |
--rm |
此容器用完就删掉,不留存,一般用在短期前台交互的情况下(默认特性是不删的) |
-p、-P、--link、--expose、EXPOSE
进行一下区分Item | Comment |
---|---|
EXPOSE |
记录服务可用的端口,但是并不创建和宿主机之间的映射,只出现在Dockerfile中 |
--expose |
运行时暴露端口,但是并不创建和主机之间的映射,同 EXPOSE 功能一样,但只出现在 CLI 中 |
-p |
创建端口映射规则,如-p ip:hostPort:containerPort , 必须指定 containerPort ,如果没有指定 hostPort, Docker会自动分配端口 |
-P |
将Dockerfile 里暴露的所有容器端口映射到动态分配的宿主机端口上 |
--link |
在容器之间创建链接,如 --link name:alias ,这会创建一系列环境变量,并在消费者容器的 /etc/hosts 文件里添加入口项,必须暴露或发布端口 |
[root@h104 ~]# docker run -it --link test-redis:redis --rm redis redis-cli -h redis -p 6379
redis:6379> get a
(nil)
redis:6379> set a b
OK
redis:6379> get a
"b"
redis:6379>
指定配置
指定配置后,映射本地卷,就可以对数据文件和日志文件的读写位置进行控制创建配置
[root@h104 x]# vim redis6379.conf
[root@h104 x]# cat redis6379.conf
daemonize no
pidfile /data/redis6379.pid
port 6379
tcp-backlog 511
timeout 1800
tcp-keepalive 0
loglevel notice
logfile "/data/redis6379.log"
databases 50
save 900 1
save 300 10
save 60 10000
stop-writes-on-bgsave-error yes
rdbcompression yes
rdbchecksum yes
dbfilename dump6379.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
appendonly no
appendfilename "appendonly6379.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
[root@h104 x]#
[root@h104 x]# diff /tmp/redis.conf ./redis6379.conf
1,2c1,2
< daemonize yes
< pidfile /var/run/redis.pid
---
> daemonize no
> pidfile /data/redis6379.pid
5c5
< timeout 0
---
> timeout 1800
8,9c8,9
< logfile ""
< databases 20
---
> logfile "/data/redis6379.log"
> databases 50
16,17c16,17
< dbfilename dump.rdb
< dir ./
---
> dbfilename dump6379.rdb
> dir /data/
25c25
< appendfilename "appendonly.aof"
---
> appendfilename "appendonly6379.aof"
[root@h104 x]#
Option | Comment |
---|---|
daemonize no |
不以后台服务的形式运行 |
timeout 1800 |
将超时时间限定为半小时,默认是不限的 |
logfile "/data/redis6379.log" |
指定日志的路径 |
databases 50 |
将数据库设为50个 |
dir /data/ |
指定存储目录 |
dbfilename dump6379.rdb |
指定数据文件名 |
appendfilename "appendonly6379.aof" |
指定append文件名 |
Note: 为什么普通情况下使用redis都是开启后台服务模式,而这里要使用前台模式呢,那是因为,容器化后,必须终结于一个前台进程,否则容器就直接退出了,这涉及容器交互模式运行和后台运行的一些特性
挂载本地卷到容器
[root@h104 x]# pwd
/tmp/x
[root@h104 x]# ls
redis6379.conf
[root@h104 x]# docker run --name myredis -d -v /tmp/x:/data redis redis-server /data/redis6379.conf
a1a4cfe7e7498827aeeb770744a9443a89212017282b41233cb3c4258a9a0b61
[root@h104 x]# docker ps -l
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a1a4cfe7e749 redis "docker-entrypoint.sh" 12 seconds ago Up 11 seconds 6379/tcp myredis
[root@h104 x]#
docker run --name myredis -d -v /tmp/x:/data redis redis-server /data/redis6379.conf
进行一下解析Option | Comment |
---|---|
docker run |
调用 docker 命令的 run 子命令 |
--name myredis |
给这个容器取名为 myredis |
-d |
后台模式运行 |
-v /tmp/x:/data |
将本地的 /tmp/x 目录挂载到容器中的 /data 目录 |
redis |
使用redis镜像 |
redis-server /data/redis6379.conf |
使用指定的配置初始化并启动redis服务 |
查看日志
因为本地目录挂载到了容器中,那么日志根据映射就直接记录到了本地[root@h104 x]# pwd
/tmp/x
[root@h104 x]# ls
redis6379.conf redis6379.log
[root@h104 x]# cat /tmp/x/redis6379.log
_._
_.-``__ ''-._
_.-`` `. `_. ''-._ Redis 3.0.7 (00000000/0) 64 bit
.-`` .-```. ```\/ _.,_ ''-._
( ' , .-` | `, ) Running in standalone mode
|`-._`-...-` __...-.``-._|'` _.-'| Port: 6379
| `-._ `._ / _.-' | PID: 1
`-._ `-._ `-./ _.-' _.-'
|`-._`-._ `-.__.-' _.-'_.-'|
| `-._`-._ _.-'_.-' | http://redis.io
`-._ `-._`-.__.-'_.-' _.-'
|`-._`-._ `-.__.-' _.-'_.-'|
| `-._`-._ _.-'_.-' |
`-._ `-._`-.__.-'_.-' _.-'
`-._ `-.__.-' _.-'
`-._ _.-'
`-.__.-'
1:M 28 Apr 14:47:24.523 # 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 28 Apr 14:47:24.523 # Server started, Redis version 3.0.7
1:M 28 Apr 14:47:24.523 # 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 28 Apr 14:47:24.524 # 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 28 Apr 14:47:24.524 * The server is now ready to accept connections on port 6379
[root@h104 x]#
使用容器的方式访问redis容器
[root@h104 x]# docker ps -l
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a1a4cfe7e749 redis "docker-entrypoint.sh" 19 minutes ago Up 19 minutes 6379/tcp myredis
[root@h104 x]# docker run -it --link myredis:redis --rm redis redis-cli -h redis -p 6379
redis:6379> CONFIG GET *pidfile*
1) "pidfile"
2) "/data/redis6379.pid"
redis:6379> CONFIG GET timeout
1) "timeout"
2) "1800"
redis:6379> CONFIG GET *logfile*
1) "logfile"
2) "/data/redis6379.log"
redis:6379> CONFIG GET *dbfilename*
1) "dbfilename"
2) "dump6379.rdb"
redis:6379> CONFIG GET *dir*
1) "dir"
2) "/data"
redis:6379> CONFIG GET *databases*
1) "databases"
2) "50"
redis:6379> info
# Server
redis_version:3.0.7
redis_git_sha1:00000000
redis_git_dirty:0
redis_build_id:6f8b503a2787e3a6
redis_mode:standalone
os:Linux 3.10.0-327.4.4.el7.x86_64 x86_64
arch_bits:64
multiplexing_api:epoll
gcc_version:4.9.2
process_id:1
run_id:280352487e387d2f70c9358b763dab833094943c
tcp_port:6379
uptime_in_seconds:1281
uptime_in_days:0
hz:10
lru_clock:2238333
config_file:/data/redis6379.conf
# Clients
connected_clients:1
client_longest_output_list:0
client_biggest_input_buf:0
blocked_clients:0
# Memory
used_memory:843568
used_memory_human:823.80K
used_memory_rss:7929856
used_memory_peak:843568
used_memory_peak_human:823.80K
used_memory_lua:36864
mem_fragmentation_ratio:9.40
mem_allocator:jemalloc-3.6.0
# Persistence
loading:0
rdb_changes_since_last_save:0
rdb_bgsave_in_progress:0
rdb_last_save_time:1461854844
rdb_last_bgsave_status:ok
rdb_last_bgsave_time_sec:-1
rdb_current_bgsave_time_sec:-1
aof_enabled:0
aof_rewrite_in_progress:0
aof_rewrite_scheduled:0
aof_last_rewrite_time_sec:-1
aof_current_rewrite_time_sec:-1
aof_last_bgrewrite_status:ok
aof_last_write_status:ok
# Stats
total_connections_received:4
total_commands_processed:19
instantaneous_ops_per_sec:0
total_net_input_bytes:757
total_net_output_bytes:1178
instantaneous_input_kbps:0.00
instantaneous_output_kbps:0.00
rejected_connections:0
sync_full:0
sync_partial_ok:0
sync_partial_err:0
expired_keys:0
evicted_keys:0
keyspace_hits:0
keyspace_misses:0
pubsub_channels:0
pubsub_patterns:0
latest_fork_usec:0
migrate_cached_sockets:0
# Replication
role:master
connected_slaves:0
master_repl_offset:0
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0
# CPU
used_cpu_sys:5.66
used_cpu_user:0.23
used_cpu_sys_children:0.03
used_cpu_user_children:0.00
# Cluster
cluster_enabled:0
# Keyspace
redis:6379> select 49
OK
redis:6379[49]> select 50
(error) ERR invalid DB index
redis:6379> select 49
OK
redis:6379[49]> get a
(nil)
redis:6379[49]> set a b
OK
redis:6379[49]> get a
"b"
redis:6379[49]> save
OK
redis:6379[49]> set b c
OK
redis:6379[49]> get b
"c"
redis:6379[49]> save
OK
redis:6379[49]> quit
[root@h104 x]#
[root@h104 x]# ls
dump6379.rdb redis6379.conf redis6379.log
[root@h104 x]# tail redis6379.log
1:M 28 Apr 14:47:24.523 # 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 28 Apr 14:47:24.524 # 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 28 Apr 14:47:24.524 * The server is now ready to accept connections on port 6379
1:M 28 Apr 15:09:11.241 * 1 changes in 900 seconds. Saving...
1:M 28 Apr 15:09:11.275 * Background saving started by pid 14
14:C 28 Apr 15:09:11.460 * DB saved on disk
14:C 28 Apr 15:09:11.461 * RDB: 6 MB of memory used by copy-on-write
1:M 28 Apr 15:09:11.515 * Background saving terminated with success
1:M 28 Apr 15:09:15.457 * DB saved on disk
1:M 28 Apr 15:09:27.514 * DB saved on disk
[root@h104 x]#
[root@h104 x]# ls
dump6379.rdb redis6379.conf redis6379.log
[root@h104 x]#
从日志中可以看到输出符合预期
数据文件也生成在了我们指定的位置
如果这个容器出现故障,我们可以将数据文件提供给其它redis容器使用,日志文件也可以使用ELK进行管理
通过以上的方式,我们成功对一个redis容器进行了客制化的修改
命令汇总
hostnamectl
docker --version
docker run --name test-redis -d redis
docker ps
docker logs 71c69b5bf62c
sysctl -a | grep vm.overcommit_memory
cat /sys/kernel/mm/transparent_hugepage/enabled
docker images | grep redis
docker run -it --link test-redis:redis --rm redis redis-cli -h redis -p 6379
docker ps -a | grep redis
cat redis6379.conf
diff /tmp/redis.conf ./redis6379.conf
docker run --name myredis -d -v /tmp/x:/data redis redis-server /data/redis6379.conf
docker ps -l
cat /tmp/x/redis6379.log
docker ps -l
docker run -it --link myredis:redis --rm redis redis-cli -h redis -p 6379
tail redis6379.log