问题：通过docker命令行，报错：Fatal error, can't open config file，在容器内执行没问题
首先，我的dockerfile如下：
```
FROM redis:latest
COPY $PWD/redis.conf /root/
RUN ["chmod", "777", "/root/redis.conf"]
CMD ["redis-server", "/root/redis.conf"]
```
redis.conf文件的内容是从这里复制的https://raw.githubusercontent...
使用`docker build  .`之后，使用`docker run -it --rm 7141cd2da206`运行，
报以下错误：
```
1:C 03 Sep 2019 12:59:48.539 # Fatal error, can't open config file '/root/redis.conf'
```
但是，我通过bash进入容器：`docker run -it --rm 7141cd2da206 bash`
执行redis-server没有任何问题，可以启动成功：
```
root@7d50439a05df:/data# ls -l /root/redis.conf 
-rwxrwxrwx 1 root root 58765 Sep  3 12:59 /root/redis.conf
```
```
root@7d50439a05df:/data# redis-server /root/redis.conf 
8:C 03 Sep 2019 13:05:46.070 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
8:C 03 Sep 2019 13:05:46.070 # Redis version=5.0.5, bits=64, commit=00000000, modified=0, pid=8, just started
8:C 03 Sep 2019 13:05:46.070 # Configuration loaded
                _._                                                  
           _.-``__ ''-._                                             
      _.-``    `.  `_.  ''-._           Redis 5.0.5 (00000000/0) 64 bit
  .-`` .-```.  ```\/    _.,_ ''-._                                   
 (    '      ,       .-`  | `,    )     Running in standalone mode
 |`-._`-...-` __...-.``-._|'` _.-'|     Port: 6379
 |    `-._   `._    /     _.-'    |     PID: 8
  `-._    `-._  `-./  _.-'    _.-'                                   
 |`-._`-._    `-.__.-'    _.-'_.-'|                                  
 |    `-._`-._        _.-'_.-'    |           http://redis.io        
  `-._    `-._`-.__.-'_.-'    _.-'                                   
 |`-._`-._    `-.__.-'    _.-'_.-'|                                  
 |    `-._`-._        _.-'_.-'    |                                  
  `-._    `-._`-.__.-'_.-'    _.-'                                   
      `-._    `-.__.-'    _.-'                                       
          `-._        _.-'                                           
              `-.__.-'                                               

8:M 03 Sep 2019 13:05:46.072 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.
8:M 03 Sep 2019 13:05:46.073 # Server initialized
8:M 03 Sep 2019 13:05:46.073 # 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.
8:M 03 Sep 2019 13:05:46.073 * Ready to accept connections

```
很困惑啊。。。！！
-----更新------
把dockerfile里redis-server替换成绝对路径又可以了：
```
FROM redis:latest
COPY $PWD/redis.conf /root/
CMD ["/usr/local/bin/redis-server", "/root/redis.conf"]
```
???

回答：用 docker inspect 可以看到，redis 的 docker 镜像的默认的 Entrypoint 是 `docker-entrypoint.sh` 。也就是说，CMD 定义的命令是由这个脚本执行的。
这个脚本的内容如下（可能不同的版本会有所不同）：
```
#!/bin/sh
set -e

# first arg is `-f` or `--some-option`
# or first arg is `something.conf`
if [ "${1#-}" != "$1" ] || [ "${1%.conf}" != "$1" ]; then
        set -- redis-server "$@"
fi

# allow the container to be started with `--user`
if [ "$1" = 'redis-server' -a "$(id -u)" = '0' ]; then
        find . \! -user redis -exec chown redis '{}' +
        exec gosu redis "$0" "$@"
fi

exec "$@"
```
可以看到，当 CMD 的第一个元素为 `redis-server` 的时候，它将当前目录（WorkingDir，通过 docker inspect 可以看到是 `/data`） 的所有文件的所有者改为了 `redis` ，然后以 `redis` 用户运行命令。
Dockerfile 里，虽然将 `/root/redis.conf` 的权限改成了 777 ，但是 `/root` 目录的权限是 700 ，redis 用户不可读，于是出错。将 `/root` 的权限也改成 777 就可以解决。
========================
由于脚本在进行精确匹配，命令改为绝对路径后将不能匹配，会进入最后一行的 exec 。此时是用 root 用户跑的，所以有读权限，可以启动。
或者说，只要 CMD 的第一个元素不是 `redis-server` ，那么用户就是 root 。所以用 bash 进容器里再跑也是没有问题的。
最后，如果 CMD 改成: `CMD redis-server /root/redis.conf` ，这个 CMD 会被改写成：`CMD ["/bin/sh", "-c", "redis-server /root/redis.conf"]` 。参考 Dockerfile / CMD 文档 ，并且可以通过 docker inspect 看到实际的 Cmd 。这时，运行的用户也是 root ，也是有读权限的，可以运行。
在命令行指定 CMD 也会使用同样的规则，参考 docerker run / COMMAND 文档 ， 可以解释相对路径会找不到文件，而改成绝对路径就可以的问题。
======================
如果 CMD 的第一个参数以 `-` 开始，或者以 `.conf` 结束，那么 `docker-entrypoint.sh` 会在前面加一个 `redis-server` 。这是其中第一个 `if` 干的事情。此时，由于第一个参数是（新插入的）`redis-server` ，所以也会以 redis 用户运行。
也就是说，启动 redis 镜像时，`redis-server` 命令其实可以不写，只写参数。比如：`CMD ["/root/redis.conf"]` 。或者，`docker run -it --rm a7f182f6c6dd /root/redis.conf` 。

标签: redis集群, redis, docker