docker 中的 httpd 无法启动

httpd in docker cannot start

我正在尝试在 docker 中安装 HTTPD,我写了一个 docker 文件,如下所示:

FROM centos

VOLUME /var/log/httpd
VOLUME /etc/httpd
VOLUME /var/www/html

# Update Yum Repostory
RUN yum clean all && \
    yum makecache fast && \
    yum -y update && \
    yum -y install httpd
RUN yum clean all
EXPOSE 80
CMD /usr/sbin/httpd -D BACKGROUND && tail -f /var/log/httpd/access_log

如果我 运行 图像没有主机卷,它可以工作,但如果我使用参数失败:

--volume /data/httpd/var/www/html:/var/www/html --volume /data/httpd/var/log:/var/log --volume /data/httpd/etc:/etc/httpd

错误信息是:

httpd: Could not open configuration file /etc/httpd/conf/httpd.conf: No such file or directory

我检查了空的挂载点:

# ll /data/httpd/etc/
total 0

但如果我不使用 "volume" 默认情况下 docker 将文件复制到临时文件夹:

# ll /var/lib/docker/volumes/04f083887e503c6138a65b300a1b40602d227bb2bbb58c69b700f6ac753d1c34/_data
total 4
drwxr-xr-x. 2 root root   35 Nov  3 03:16 conf
drwxr-xr-x. 2 root root   78 Nov  3 03:16 conf.d
drwxr-xr-x. 2 root root 4096 Nov  3 03:16 conf.modules.d
lrwxrwxrwx. 1 root root   19 Nov  3 03:16 logs -> ../../var/log/httpd
lrwxrwxrwx. 1 root root   29 Nov  3 03:16 modules -> ../../usr/lib64/httpd/modules
lrwxrwxrwx. 1 root root   10 Nov  3 03:16 run -> /run/httpd

所以我很困惑,为什么 docker 拒绝将它们复制到指定位置?以及如何解决这个问题?

这确实是记录在案的行为:

Volumes are initialized when a container is created. If the container’s base image contains data at the specified mount point, that existing data is copied into the new volume upon volume initialization. (Note that this does not apply when mounting a host directory.)

即当您挂载 /etc/httpd--卷 /data/httpd/etc:/etc/httpd 时,不会复制任何数据.

您还可以查看 https://github.com/docker/docker/pull/9092 以更详细地讨论为什么它以这种方式工作(如果您有兴趣)。

通常的解决方法是将初始数据复制到 ENTRYPOINT 或 CMD 脚本内的卷文件夹(从容器内), 万一它是空的。

请注意,您的初始数据集必须保存在卷文件夹之外(例如 /opt 中的 .tar 文件),因为卷文件夹将被安装在上面的主机文件夹隐藏它。

下面给出了一个示例 Dockerfile 和脚本,它演示了行为:

示例 Dockerfile

FROM debian:stable
RUN mkdir -p /opt/test/; touch /opt/test/initial-data-file
VOLUME /opt/test

示例脚本(尝试各种卷映射)

#Build image
>docker build -t volumetest .

Sending build context to Docker daemon  2.56 kB
Step 0 : FROM debian:stable
---> f7504c16316c
Step 1 : RUN mkdir -p /opt/test/; touch /opt/test/initial-data-file
---> Using cache
---> 1ea0475e1a18    
Step 2 : VOLUME /opt/test
---> Using cache
---> d8d32d849b82
Successfully built d8d32d849b82

#Implicit Volume mapping (as defined in Dockerfile)
>docker run --rm=true volumetest ls -l /opt/test
total 0
-rw-r--r-- 1 root root 0 Nov  4 18:26 initial-data-file

#Explicit Volume mapping
> docker run --rm=true --volume /opt/test volumetest ls -l /opt/test/
total 0
-rw-r--r-- 1 root root 0 Nov  4 18:26 initial-data-file

#Explicitly Mounted Volume
>mkdir test
>docker run --rm=true --volume "$(pwd)/test/:/opt/test" volumetest ls -l /opt/test
total 0

这是一个简单的入口点脚本,说明了可能的解决方法:

#!/bin/bash
VOLUME=/opt/test
DATA=/opt/data-volume.tar.gz

if [[ -n $(find "$VOLUME" -maxdepth 0 -empty) ]]
then
    echo Preseeding VOLUME $VOLUME with data from $DATA...
    tar -C "$VOLUME" -xvf "$DATA" 
fi

"$@"

将以下内容添加到 Dockerfile

COPY data-volume.tar.gz entrypoint /opt/
ENTRYPOINT ["/opt/entrypoint"]

第一个运行:

>docker run --rm=true --volume "$(pwd)/test/:/opt/test" volumetest ls -l /opt/test
Preseeding VOLUME /opt/test with data from /opt/data-volume.tar.gz...
preseeded-data
total 0
-rw-r--r-- 1 1001 users 0 Nov  4 18:43 preseeded-data

后续 运行s:

>docker run --rm=true --volume "$(pwd)/test/:/opt/test" volumetest ls -l /opt/test
ls -l /opt/test
total 0
-rw-r--r-- 1 1001 users 0 Nov  4 18:43 preseeded-data

请注意,卷文件夹将填充数据, 如果之前完全是空的。