Doker tini 进程管理器

tini 容器 init  是一个最小化的  init  系统,运行在容器内部,用于启动一个子进程,并等待进程退出时清理僵尸和执行信号转发。 这是一个替代庞大复杂的 systemd 体系的解决方案,已经集成到 Docker 1.13 中,并包含在 Docker CE 的所有版本。

Tini 的优点:

  • tini 可以避免应用程序生成僵尸进程
  • tini 可以处理 Docker 进程中运行的程序的信号,例如,通过 Tini, SIGTERM  可以终止进程,不需要你明确安装一个信号处理器

我们为什么要使用 Tini,可以参考  What is advantage of Tini?  后续我再整理一下

要激活 Tini,在  docker run  命令中传递  --init  参数就可以。

在 Docker 中,只需要加载 Tini 并传递运行的程序和参数给 Tini 就可以:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10

# Add Tini
ENV TINI_VERSION v0.19.0
ADD https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini /tini
RUN chmod +x /tini
ENTRYPOINT ["/tini", "--"]

# Run your program under Tini
CMD ["/your/program", "-and", "-its", "arguments"]
# or docker run your-image /your/program ...

上述 Dockerfile 中,通过  ENTRYPOINT  启动  tini  作为进程管理器,然后再通过  tini  运行  CMD  指定的程序命令。

备注

tini release download  提供了不同处理器架构的

如果要使用 tini 签名,请参考  tini 容器 init  发行文档

  • 创建一个 Dockerfile 如下

docker_tini/Dockerfile.ssh_exit_0

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17

 FROM docker.io/centos:7

 RUN yum clean all && yum -y update && yum install -y net-tools iproute openssh-clients openssh-server which sudo
 RUN groupadd -g 500 admin && useradd -g 500 -u 500 -d /home/admin -m admin
 RUN echo 'admin ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers

 # Add Tini
 ENV TINI_VERSION v0.19.0
 ADD https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini /tini
RUN chmod +x /tini
ENTRYPOINT ["/tini", "--"]

RUN ssh-keygen -A
# Run your program under Tini
# CMD ["/your/program", "-and", "-its", "arguments"]
CMD ["/usr/sbin/sshd"]
  • 构建镜像: docker build -t local:ssh - < Dockerfile.ssh_exit_0
  • 运行容器: docker run -itd –hostname myssh –name myssh local:ssh

但是,此时检查  docker ps  却看不到  myssh  这个容器。这是为什么呢?

  • 执行检查: docker ps –all

可以看到原来容器结束了,并且退出返回值是  0 ,这意味着执行成功:

CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 21fb4926ac47 local:ssh “/tini – /usr/sbin/…” 4 minutes ago Exited (0) 4 minutes ago myssh

WHY?

原因是 docker 只检测前台程序是否结束,对于  sshd  这样的后台服务,运行以后返回终端,则 docker 认为顺利结束了,就停止了容器。解决的方法,一般是运行一个前台程序,例如服务不放到后台运行,或者索性再执行一个  bash ,甚至我们可以编译一个  pause  执行程序(通过 c 的 pause 实现) 避免前台程序结束

  • 尝试添加  bash  作为结尾: CMD ["/usr/sbin/sshd && /bin/bash"]

但是很不幸,执行以后退出返回码是错误的 127

我参考了一下之前的  Docker 容器中运行 ssh 服务  方法修订成:

CMD [“bash -c ‘/usr/sbin/sshd && /bin/bash’”]

依然错误,比较难处理  ' ' ,所以还是改写成脚本来执行比较方便

  • 创建一个  entrypoint.sh  脚本

docker_tini/entrypoint_ssh_bash

1
2

/usr/sbin/sshd && /bin/bash
  • 修订 Dockerfile 如下,将这个脚本复制到镜像内部并作为 entrypoint

docker_tini/Dockerfile.ssh_bash

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
 FROM docker.io/centos:7

 RUN yum clean all && yum -y update && yum install -y net-tools iproute openssh-clients openssh-server which sudo
 RUN groupadd -g 500 admin && useradd -g 500 -u 500 -d /home/admin -m admin
 RUN echo 'admin ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers

 # Add Tini
 ENV TINI_VERSION v0.19.0
 ADD https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini /tini
RUN chmod +x /tini
ENTRYPOINT ["/tini", "--"]

COPY entrypoint_ssh_bash /entrypoint.sh
RUN chmod +x /entrypoint.sh

RUN ssh-keygen -A
# Run your program under Tini
# CMD ["/your/program", "-and", "-its", "arguments"]
CMD ["/entrypoint.sh"]
  • 现在我们重新构建镜像: docker rm myssh docker rmi local:ssh docker build -t local:ssh - < Dockerfile.ssh_bash docker run -itd –hostname myssh –name myssh local:ssh

现在就可以可以正常运行 ssh 了。

不过,你会觉得,这样有什么优势呢?我们不能直接执行 shell 脚本么

原因是  tini  提供了很好到进程管理功能,能够转发信号给管理的子进程,这样就方便在  Kubernetes Atlas  中调度管理。

需要注意的是,如果在  entrypoint  最后调用了  bash ,则通过  docker attach <contianer>  访问终端时,和  docke run ... /bin/bash  一样,绝对不能执行  ctrl-d  退出,否则会直接结束容器。

上面我也提到了,如果不使用  bash  结束,我们也可以编译一个  pause  程序,请参考  Void (Linux) distribution (一个完全独立的发行版)提供的工具集  void-runit  中的  pauese.c

上面我们已经实现了一个在 tini 下启动 sshd 的方法,那么我们现在来构建多个服务

  • 构建一个多服务启动的脚本,这里我们启动案例是  ssh  和  cron

entrypoint_ssh_cron_bash 脚本

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20

#!/usr/bin/env bash

sshd() {
    /usr/bin/ssh-keygen -A
    /usr/sbin/sshd
}

crond() {
    /usr/sbin/crond
}

main() {
    sshd
    crond
    # 这里最后执行/bin/bash在docker中没有问题,但是K8s检测程序运行结束会判断pod终止crash,所以无法running
    /bin/bash
}

main

警告

这里的  entrypoint_ssh_cron_bash  脚本实际上有一个缺陷,只能在 Docker 中正常工作,应用到 Kubernetes 上会出现 pod 不断 Crash。原因在  kind 部署 fedora-dev-tini (tini 替代 systmed)  有详细分析以及对应的改进

  • 修订 Dockerfile 如下,将这个脚本复制到镜像内部并作为 entrypoint

将 entrypoint_ssh_cron_bash 脚本复制到容器内部作为 tini 调用的 /entrypoint.sh 脚本来启动多个服务

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
FROM docker.io/centos:7

RUN yum clean all && yum -y update && yum install -y net-tools iproute openssh-clients openssh-server crontabs which sudo
RUN groupadd -g 500 admin && useradd -g 500 -u 500 -d /home/admin -m admin
RUN echo 'admin ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers

# Add Tini
ENV TINI_VERSION v0.19.0
ADD https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini /tini
RUN chmod +x /tini
ENTRYPOINT ["/tini", "--"]

COPY entrypoint_ssh_cron_bash /entrypoint.sh
RUN chmod +x /entrypoint.sh

# Add ssh public key for login
RUN mkdir -p /home/admin/.ssh
COPY admin.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 ssh-keygen -A
# Run your program under Tini
# CMD ["/your/program", "-and", "-its", "arguments"]
CMD ["/entrypoint.sh"]

转载来自于。 转载:https://cloud-atlas.readthedocs.io/zh-cn/latest/

Licensed under CC BY-NC-SA 4.0
最后更新于 Jan 06, 2025 05:52 UTC
comments powered by Disqus
Built with Hugo
主题 StackJimmy 设计
Caret Up