Docker容器启动时启动服务

使用Docker快速部署不同版本CentOS容器介绍了如何构建运行CentOS的容器,这样我们可以快速clone出多个以相同image构建的CentOS环境。

Dockerfile中有很多RUN指令告诉docker在构建容器的时候需要完成哪些工作。但是要注意,这个RUN指令只在构建容器的时候运行一次,用于初始化容器。但是容器停止然后再次启动,则不会运行。

这样,对于我们每次启动容器都要运行的服务,该如何调用呢?

docker提供了另外一个指令 CMD,该指令在容器每次启动时都会执行,这样就可以在容器中启动服务,例如sshd

举例:

这里同时添加了一个authorized_keys到容器中方便ssh登陆,所以在Dockerfile的相同目录下还要再准备一个从authorized_keys文件

FROM docker.io/centos:7
MAINTAINER vincent huatai <vincent@huatai.me>

RUN yum clean all
RUN yum -y update

#RUN yum -y install which sudo mlocate net-tools rsyslog file ntp ntpdate \
#wget tar bzip2 screen sysstat unzip nfs-utils parted lsof man bind-utils \
#gcc gcc-c++ make telnet flex autoconf automake ncurses-devel crontabs \
#zlib-devel git openssh-clients openssh-server initscripts
RUN yum -y install which sudo openssh-clients openssh-server initscripts

# Prepare sshd host key
RUN ssh-keygen -A

# add account "admin" and give sudo privilege
RUN groupadd -g 505 admin
RUN useradd -g 505 -u 505 -d /home/admin -m admin
RUN usermod -aG wheel admin
RUN echo "%wheel        ALL=(ALL)       NOPASSWD: ALL" >> /etc/sudoers

# Add ssh public key for login
RUN mkdir -p /home/admin/.ssh
ADD authorized_keys /home/admin/.ssh/authorized_keys
RUN chown -R admin:admin /home/admin/.ssh
RUN chmod 600 /home/admin/.ssh/authorized_keys
RUN chmod 700 /home/admin/.ssh

# run service when container started
EXPOSE 22
#CMD /usr/sbin/sshd,this is not a interactive shell
CMD ["/usr/sbin/sshd", "-D"]

sshd的参数-D是一个前台debug参数:

 -D      When this option is specified, sshd will not detach and does not become a daemon.  This allows easy monitoring of sshd.

参考Dockerize an SSH service

注意:这里EXPOSE 22(等同于命令行--expose=22-p 22)会将容器的22端口随机映射到host主机的网络对外网络接口上,此时就可以通过docker port <容器名>查看端口映射,即可使用动态映射的端口从外部网络访问虚拟容器的ssh服务。

如果要固定映射,则配置为EXPOSE 22:8022;命令行使用-p 22:8022将容器ssh端口映射成物理服务器的8022端口。

  • 构建镜像

docker build -t local:centos7 .
  • 创建容器

docker run -d -P --hostname dev7 --name dev7 local:centos7

这里不要使用docker run -it进入交互模式(最后启动的是bash会导致替换掉Dockerfile中的最后的CMD ["/usr/sbin/sshd", "-D"]

-- 注意:Dockerfile最后的CMD指令会被docker run ... /bin/bash替换,命令行的CMD优先级高。

如果使用如下名林启动/bin/bash则会进入交互模式,此时不会启动sshd,但是可以在交互模式中使用手工命令/usr/sbin/sshd启动ssh服务:

docker run -it --hostname dev7 --name dev7 local:centos7 /bin/bash

Dockerfile中CMDENDPOINT的区别

上述容器化sshd有一个非常麻烦的地方是,无法docker attach访问容器内部系统(因为最后一个CMD/usr/sbin/sshd -D占用了控制台),对于传统的系统维护带来不便。

但是如上所述,如果在docker run命令行传递需要运行的指令/bin/bash虽然可以获得终端交互,但是带来上述CMD ["/usr/sbin/sshd", "-D"]被覆盖,就不能自动启动ssh服务。

解决的方法是使用ENDPOINT,这个方式的指令不会被命令行指令覆盖。此外,可以在ENDPOINT部分使用&&来连续处理多个服务启动,并最后执行/bin/bash来获得一个交互终端:

ENTRYPOINT /usr/sbin/sshd && /bin/bash

然后按照以下方式创建镜像和启动容器:

docker build -t local:centos7 .

docker run -itd --hostname dev7 --name dev7 local:centos7

注意

  • docker run参数要使用-it,这样表示启动一个pty(-t)和交互模式(-i),以避免/bin/bash指令立即结束。如果没有-it参数,则容器瞬间启动并结束(因为/bin/bash已经执行结束了)。

  • docker run参数使用-d表示detach,这样可以断开容器终端,让容器中的/bin/bash继续运行。这样也就达到了随时可以重新用docker attach dev7重新连接到虚拟容器进行进一步操作。

完整Dockerfile

# HowTo use this dockerfile?
# ------ for example:
# 1. create image which name "local:centos7"
# 2. create container which name "dev7"
# --------------------------------------
# docker build -t local:centos7 .
# docker run -itd --hostname dev7 --name dev7 local:centos7

FROM docker.io/centos:7
MAINTAINER vincent huatai <vincent@huatai.me>

RUN yum clean all
RUN yum -y update

RUN yum -y install which sudo openssh-clients openssh-server initscripts

# Prepare sshd host key
RUN ssh-keygen -A

# add account "admin" and give sudo privilege
RUN groupadd -g 505 admin
RUN useradd -g 505 -u 505 -d /home/admin -m admin
RUN usermod -aG wheel admin
RUN echo "%wheel        ALL=(ALL)       NOPASSWD: ALL" >> /etc/sudoers

# Add ssh public key for login
RUN mkdir -p /home/admin/.ssh
ADD authorized_keys /home/admin/.ssh/authorized_keys
RUN chown -R admin:admin /home/admin/.ssh
RUN chmod 600 /home/admin/.ssh/authorized_keys
RUN chmod 700 /home/admin/.ssh

# run service when container started - sshd
EXPOSE 22
#CMD ["/usr/sbin/sshd", "-D"]

# ----------
# WANT run sshd and get a bash
# ENTRYPOINT will not be override by commandline
# ----------
ENTRYPOINT /usr/sbin/sshd && /bin/bash

其他服务启动案例

以下案例同时创建了共享存储和端口映射

# creat host share storage volume
docker volume create share-data

# create container with port 8000 map
docker run -itd -p 22 -p 8000:8000 --memory=2048M --cpus="1.5" --hostname dev7 --name dev7 \
-v share-data:/data local:centos7

或者简化一些:

docker run -itd --hostname dev7 --name dev7 -v share-data:/data local:centos7

最新的Dockerfile见我的DevOps: Docker: CentOS7

参考

Last updated