Docker含httpd与memcached的镜像启动容器时memcached未自启的解决方法
问题根因
- Dockerfile中重复定义
ENTRYPOINT指令。按照Docker的运行规则,同一文件内书写多次ENTRYPOINT时,只有最后一条配置会生效,前面的配置会被完全覆盖。原配置先后写了httpd、memcached两组ENTRYPOINT,从机制上就无法同时拉起两个服务。 - 多服务启动逻辑不符合容器运行规范。容器默认需要以前台常驻进程作为PID1维持生命周期,不能通过拆分多个ENTRYPOINT启动多个服务;且容器内默认没有完整的init运行环境,
systemctl这类依赖systemd生态的命令无法正常执行,哪怕配置了enable/start指令也不会生效。 - memcached启动参数书写不规范。原配置的memcached命令带了无意义的
start参数,缺少-d后台运行标识,同时把监听IP直接放在命令末尾而非通过-l参数指定,这类错误写法会导致服务无法按预期拉起。
可行的配置方案
单容器内启动两个服务的核心逻辑是:容器启动时先把需要后台运行的memcached拉起,再把需要前台常驻的httpd设为PID1主进程,保证容器不会提前退出。根据实际场景可以选择两种实现方式:
轻量Shell脚本方案(无额外依赖,适合服务数量少的场景)
直接修改原Amazon Linux 2版本的Dockerfile,删除重复的ENTRYPOINT配置,通过启动脚本串联两个服务的启动流程:
FROM amazonlinux:2 MAINTAINER tian # 原有软件安装步骤保持不变 RUN yum update -y && \ yum install -y tar unzip wget procps telnet httpd libevent libevent-devel gcc make && \ wget http://www.memcached.org/files/memcached-1.4.24.tar.gz && \ tar xvzf memcached-1.4.24.tar.gz && \ /memcached-1.4.24/configure --enable-64bit && \ make && make install && \ rm -rf memcached-1.4.24.tar.gz memcached-1.4.24 # 编写统一启动脚本 RUN echo '#!/bin/bash\n\ # 后台启动memcached,通过-l参数指定监听地址\n\ memcached -u nobody -m 512 -p 11211 -l 127.0.0.1 -d\n\ # 以前台模式启动httpd作为主进程,保证容器不退出\n\ exec /usr/sbin/httpd -D FOREGROUND' > /start.sh && chmod +x /start.sh # 仅保留一个ENTRYPOINT指向启动脚本 ENTRYPOINT ["/start.sh"] EXPOSE 80 11211
方案说明:
- 脚本先执行memcached的后台启动命令,修正原有参数错误(去掉多余的
start参数,加上-d后台标识,通过-l正确指定监听地址) - 最后通过
exec命令启动httpd,让httpd成为PID1进程,保证容器能正常接收停止信号,不会出现进程僵死的问题。 - 两个服务不会抢占前台运行位置:memcached作为后台进程运行,httpd作为主进程维持容器整个生命周期。
进程管理器方案(适合多服务扩展场景)
如果后续需要部署更多服务,可以引入supervisord作为统一的进程管理器,替代手写shell脚本,自动完成服务拉起、故障重启的工作。基于UBI7镜像的修改示例如下:
FROM registry.access.redhat.com/ubi7/ubi:latest MAINTAINER tian # 安装基础软件与supervisord RUN yum update -y && \ yum install -y unzip httpd wget telnet memcached libmemcached supervisor # 编写supervisord配置,同时管理两个服务 RUN echo '[program:memcached]\n\ command=/usr/bin/memcached -u nobody -m 512 -p 11211 -l 127.0.0.1\n\ autostart=true\n\ autorestart=true\n\ \n\ [program:httpd]\n\ command=/usr/sbin/httpd -D FOREGROUND\n\ autostart=true\n\ autorestart=true' > /etc/supervisord.conf # 仅保留一个ENTRYPOINT启动supervisord ENTRYPOINT ["/usr/bin/supervisord", "-c", "/etc/supervisord.conf"] EXPOSE 80 11211
方案说明:
- supervisord本身作为PID1运行,不需要依赖系统自带的systemd,从根本上解决systemctl命令无法执行的问题
- 配置中开启了
autorestart,任意一个服务异常退出都会被自动拉起,比手写shell脚本的运行稳定性更高。
注意:不推荐在容器内通过
systemctl管理服务,因为容器启动时没有加载systemd的运行环境,哪怕加了特权参数也会带来不必要的安全风险。
内容的提问来源于stack exchange,提问作者jlu-tianji
相关产品推荐
相关产品推荐

