内容简介:在一个Docker Container中运行多个服务?打扰了。Docker,或说任何基于在实际中,使用
在一个Docker Container中运行多个服务?打扰了。
0x00 前言
Docker,或说任何基于 内核namespace
的轻量级进程隔离技术,在设计之初,都不是为了当作虚拟机使用的。也就是说,其中运行的并不是一个完整的操作系统。包括 Docker 官方,也是推荐在一个Container内仅运行一个服务。如果需要运行多个服务,应通过 docker run --link
或者 docker-compose
来关联多个容器。但是在实际的应用中,我们经常希望将一个完整的可运行环境打包成一个 docker image
,不再依赖其他的容器。比如在CTF比赛中,将多个服务打包成一个Image,可以有效地提高在环境受损后恢复的效率。在经历了多场比赛,看过各种大师傅用各种奇怪的姿势完成这个任务后,觉得应该好好的讨论一下这个问题。
0x01 错误的姿势
- 使用upstart的启动方式
# Dockerfile From ubuntu:14.04 RUN apt-get update && apt-get upgrade -y && apt-get install mysql apache2 php 7.0 ADD web /var/www/html RUN service mysql start && /var/www/html/init_sql.sh && service mysql stop CMD service mysql start && service apache2 start && while true; do sleep 10;done
- 使用systemd的启动方式
# Dockerfile From ubuntu:16.04 RUN apt-get update && apt-get upgrade -y && apt-get install mysql apache2 php7.0 ADD web /var/www/html RUN systemctl start mysql && /var/www/html/init_sql.sh && systemctl stop mysql CMD systemctl start mysql && systemctl start apache2 && while true; do sleep 10;done
- 使用启动脚本启动多个服务
# Dockerfile From ubuntu:16.04 RUN apt-get update && apt-get upgrade -y && apt-get install mysql apache2 php7.0 ADD web /var/www/html ADD entrypoint.sh /sbin/ RUN chmod +x /sbin/entrypoint.sh /var/www/html/init_sql.sh&& \ /etc/init.d/mysql start && /var/www/html/init_sql.sh && /etc/init.d/mysql stop CMD /sbin/entrypoint.sh
#!/bin/bash # entrypoint.sh /usr/bin/mysqld start & /usr/bin/httpd & while true do sleep 100 done
在实际中,使用 方法1
或者 方法2
很大几率无法完成将多个服务跑在同一个container中的任务。 方法3
虽然可以,但仍然存在一些问题:
SIGTERM
方法1
和 方法2
不能成功,是因为docker只是一个进程隔离的沙箱环境,并不是真正的虚拟机。而 service xxx start
和 systemctl start xxx
分别是 upstart
和 systemd
这两个 /sbin/init
进程的替代者的服务管理命令。而 upstart
和 systemd
都要求系统必须是物理机或虚拟机,并不支持作为container的 init
进程。方法3存在问题是因为,在正常的系统中, init
进程永远占用 PID=1
的位置,回收僵尸进程、处理未处理的信号等都是由 init
进程帮我们完成的,一个子进程如果失去了父进程,也会由 init
进程接管。但是在container中, init
进程并不存在, PID=1
的进程是我们在 Dockerfile
中定义的 Entrypoint
或最后一个 CMD
指定的命令。
root@vpscn:/var/lib/docker# docker exec -it hackmd sh /hackmd # ps -ef PID USER TIME COMMAND 1 hackmd 1:03 node app.js 42 hackmd 0:00 /usr/local/bin/node ./lib/workers/dmpWorker.js 62 root 0:00 sh 69 root 0:00 ps -ef
因此,对于启动方法3的container,我们应该在启动时加上 --init
参数,来强制使用 tini
作为 init
进程。但是就算这样,在服务多了之后,进行重启等操作仍然很繁琐。
0x02 推荐的姿势
作为一个~~金牌运维~~打杂的,简单谈谈我常用的方法。
首先推荐一个超级好用的基础镜像 phusion/baseimage
。截至SUCTF2018环境准备完成时,该镜像的最新版本是 0.10.1
,基于 ubuntu 16.04
。我们常用的 apt-get
等命令都可以无缝兼容。 phusion/baseimage
采用了作者自己开发的一个基于 python
的 init
进程作为Container的 Entrypoint
,采用 runit
作为服务管理器。这个基础镜像还是在Coding打杂的时候知道的, Coding ~~WebIDE~~ Studio
的Web Terminal也是基于这个镜像做的。NUAACTF/SUCTF的PWN题基础镜像 ctf-xinetd
也是基于这个镜像做的。
然后直接贴个在SUCTF2018运维期间写的 Dockerfile
#Dockerfile FROM phusion/baseimage:0.10.1 MAINTAINER Yibai Zhang <xm1994@outlook.com> RUN sed -i 's/archive.ubuntu.com/mirrors.aliyun.com/g' /etc/apt/sources.list &&\ sed -i 's/security.ubuntu.com/mirrors.aliyun.com/g' /etc/apt/sources.list &&\ apt-get update && apt-get install -y apache2 libapache2-mod-php php-mysql mariadb-server &&\ apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* /var/www/html/* RUN mkdir -p /etc/service/apache2/ && \ printf "#!/bin/sh\n\ntrap \"apachectl -k graceful-stop\" 1 2 3 6 15\n\nexec /usr/sbin/apachectl -D FOREGROUND\n" > /etc/service/apache2/run &&\ chmod +x /etc/service/apache2/run && mkdir -p /etc/service/mysql/ &&\ printf "#!/bin/sh\n\ntrap \"mysqladmin -uroot -psuCTF_P1us_1s shutdown\" 1 2 3 6 15\n\nexec /usr/bin/mysqld_safe" > /etc/service/mysql/run &&\ mkdir -p /var/run/mysqld/ && chown mysql:mysql /var/run/mysqld &&\ chmod 700 /etc/service/mysql/run /etc/service/apache2/run COPY web /var/www/html COPY flag /flag RUN echo "secure-file-priv=/var/www/" >>/etc/mysql/mariadb.conf.d/50-server.cnf && chmod -R 777 /var/www/html/favicon COPY init_sql.sh /tmp/init_sql.sh RUN chmod +x /tmp/init_sql.sh && bash -c "/tmp/init_sql.sh" && rm /tmp/init_sql.sh EXPOSE 80
#!/usr/bin/env bash #init_sql.sh mysqld_safe & echo -n "Waiting for mysql startup" while ! mysqladmin --host="localhost" --silent ping ; do echo -n "." sleep 1 done echo mysql -uroot <<EOF UPDATE mysql.user SET Password=PASSWORD('XXXXXX'), plugin = '' WHERE User='root'; create database calc; use calc; create table user( id INT NOT NULL AUTO_INCREMENT primary key, username varchar(32) NOT NULL, password varchar(32) NOT NULL )ENGINE=InnoDB DEFAULT CHARSET=utf8; insert into user values(1,'admin','aa67095d8e65d624548cb6b50bd4778e'); create table file( id INT NOT NULL AUTO_INCREMENT primary key, filename varchar(32) NOT NULL, filehash varchar(32) NOT NULL, sig varchar(120) NOT NULL )ENGINE=InnoDB DEFAULT CHARSET=utf8; create table flag( flag varchar(120) primary key )ENGINE=InnoDB DEFAULT CHARSET=utf8; insert into flag values('SUCTF{a_very_long_long_long_long_long_fake_flag_d}'); grant SELECT, INSERT on calc.user to 'suctf'@localhost identified by 'suctf'; grant SELECT, INSERT, UPDATE on calc.file to 'suctf'@localhost ; grant SELECT on calc.flag to 'suctf'@localhost ; FLUSH PRIVILEGES; EOF mysqladmin -uroot -pXXXXXX shutdown
这里着重看一下 printf "#!/bin/sh\n\ntrap \"apachectl -k graceful-stop\" 1 2 3 6 15\n\nexec /usr/sbin/apachectl -D FOREGROUND\n" > /etc/service/apache2/run
,这个命令就是在创建runit启动脚本。具体的说明可以去看 phusion/baseimage
或者 runit
的手册。执行完成后会在 /etc/service/apache2/run
下面生成如下内容的脚本
#!/bin/sh trap "apachectl -k graceful-stop" 1 2 3 6 15 exec /usr/sbin/apachectl -D FOREGROUND
这个脚本会作为runit的子进程运行,并将Apache2保持在前台运行。在接收到 1 2 3 6 15
这几个信号的时候友好的(graceful)结束Apache2。如果在运行中需要重启Apache服务,只需要运行 docker exec container_name sv restart apache2
即可。通过这种方式,在Container停止的时候也可以通知相关的进程,而不是直接全部杀死,更可以保证服务的完整性。~~虽然在比赛中基本挂了就要恢复环境根本不需要保证完整性。~~
以上所述就是小编给大家介绍的《如何科学的在Docker Container中运行多个服务》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- 运行多个 npm script
- 多个安卓墙纸APP运行恶意广告
- ansible文件内容替换+在远程主机上运行多个command
- UP Core开发板将于8月份出货,可运行多个操作系统
- 如何从PHP脚本(如批处理文件)中运行多个PHP脚本?
- 开源组件漏洞对运行多个CMS的站点构成威胁(CVE-2019-11831)
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Writing Apache Modules with Perl and C
Lincoln Stein、Doug MacEachern / O'Reilly Media, Inc. / 1999-03 / USD 39.95
Apache is the most popular Web server on the Internet because it is free, reliable, and extensible. The availability of the source code and the modular design of Apache makes it possible to extend Web......一起来看看 《Writing Apache Modules with Perl and C》 这本书的介绍吧!