Docker,或说任何基于内核namespace的轻量级进程隔离技术,在设计之初,都不是为了当作虚拟机使用的。也就是说,其中运行的并不是一个完整的操作系统。包括Docker官方,也是推荐在一个Container内仅运行一个服务。如果需要运行多个服务,应通过docker run --link 或者docker-compose来关联多个容器。但是在实际的应用中,我们经常希望将一个完整的可运行环境打包成一个docker image,不再依赖其他的容器。比如在CTF比赛中,将多个服务打包成一个Image,可以有效地提高在环境受损后恢复的效率。在经历了多场比赛,看过各种大师傅用各种奇怪的姿势完成这个任务后,觉得应该好好的讨论一下这个问题。
0x01 错误的姿势
使用upstart的启动方式
1 2 3 4 5 6
# Dockerfile From ubuntu:14.04 RUN apt-get update && apt-get upgrade -y && apt-get install mysql apache2 php7.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的启动方式
1 2 3 4 5 6
# 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
使用启动脚本启动多个服务
1 2 3 4 5 6 7 8
# 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
1 2 3 4 5 6 7 8 9
#!/bin/bash
# entrypoint.sh /usr/bin/mysqld start & /usr/bin/httpd & while true do sleep 100 done
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