Dockerfile最佳实践

在生产环境中一般我们会对基本的环境进行自构建,从而利用images的分层特性去层层构建上层的业务镜像。

1.默认情况下我们会首先构建一个基本的base镜像,这个镜像可能包含了linux具体的发行版本,以及基本的软件包,比如wget,vi等。在该层面上,镜像的改动会很少,频次也会很低。

2.其次我们可以在base镜像之上构建新的平台镜像,比如说ssh,java,tomcat等。在基础环境层,相比较上一层来说修改频次稍微会有点大,因为可能涉及到基本软件的版本调整或者参数调整。

3.然后在可以在基本的平台镜像之上构建业务镜像,业务镜像是可以直接启动应用程序的,也就是需要启动服务进程的。该层镜像就是直接和业务代码融合的镜像,随着业务的更新,镜像也会频繁的改动上线。

问题:如果我们构建业务镜像中默认需要启动多个服务,比如需要启动sshd和tomcat或者是一个nginx,那么就不能通过构建镜像的时候去使用CMD命令,因为CMD命令会继承上层images的CMD命令,从而导致上层的CMD命令失效。那么想要既继承上层的sshd,又需要启动业务进程,普通的方式可以采用脚本定义,并在业务镜像层进行RUN脚本。

所以比较好的方法:使用supervisord来管理images中的多个服务进程。可以在基本镜像层进行构建supervisord镜像,然后在上层业务层通过配置supervisord.conf来管理对个进程,实现一个容器中启动多个服务进程。

构建无需启动服务的pass层镜像

该环节是提供给用户基本的软件运行环境,用户可以通过bash登录去启动业务程序。而根据业务的变化特征,以及基础服务的抽象程度,我们可以将该层的image镜像分成以下三个image进行叠加。

构建符合实际业务场景的base镜像

注意:给image中打入sshd服务的主要原因还是想尽可能的满足用户当前的使用习惯,同时又能够充分利用docker image的特性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
FROM centos6.8-base
MAINTAINER xuxuebiao
RUN ssh-keygen -q -N “” -t dsa -f /etc/ssh/ssh_host_dsa_key ;\
ssh-keygen -q -N “” -t rsa -f /etc/ssh/ssh_host_rsa_key ;\
sed -ri ‘s/session required pam_loginuid.so/#session required pam_loginuid.so/g’ /etc/pam.d/sshd ;\
mkdir -p /root/.ssh && chown root.root /root && chmod 700 /root/.ssh ;\
sed -ri ‘s/#Port 22/Port 52568/g’ /etc/ssh/sshd_config ;\
echo ‘root:redhat’ | chpasswd
EXPOSE 52568
ENV LANG=zh_CN.UTF-8;\
LC_ALL=zh_CN.UTF-8;\
TZ “Asia/Shanghai”;\
TERM xterm
CMD /usr/sbin/sshd -D
1
#docker build -t centos6.8-sshd .

构建上层基本软件环境

注意:上层SSHD镜像默认使用CMD启动了一个sshd服务,因此这层PAAS层无法直接启动nginx和tomcat,本层只是构建了一个基本环境,容器启动后需要登录bash中执行脚本进行启动。这样交付的环境其实就相当于PAAS层的环境

构建一个基于jdk7tomcat6的基本镜像:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
FROM centos6.8-sshd
MAINTAINER “xuxuebiao”
ENV TZ “Asia/Shanghai”;\
PATH $PATH:/export/data/
RUN useradd admin;\
mkdir -p /export/servers/{jdk1.7.0_71,tomcat6.0.33,nginx};\
mkdir -p /export/{App,auto_deploy,Config,data,Data,Domains,home,Logs,servers,Shell};
WORKDIR /export/data/
EXPOSE 80
EXPOSE 8080
ADD jdk1.7.0_71 /export/servers/jdk1.7.0_71
ADD tomcat6.0.33 /export/servers/tomcat6.0.33
ADD profile /etc/profile
ADD nginx /export/servers/nginx
ADD auto-add-tomcat /home/admin/
COPY start_nginx /etc/init.d/nginx
COPY init_nginx.sh /export/Shell/
RUN chmod a+x /etc/init.d/nginx;\
chmod a+x /export/Shell/init_nginx.sh;\
chown admin.admin -R /export/ /home/admin/

构建一个基于python27的基本环境,环境中本身已经安装各种第三方程序库:

1
2
3
4
5
6
7
8
9
FROM centos6.8-sshd
MAINTAINER biaoge
ADD python27 /usr/local/python27
RUN ln -s /usr/local/python27/bin/python2.7 /usr/local/bin/python27 ;\
ln -s /usr/local/python27/bin/pip /usr/local/bin/pip;\
ln -s /usr/local/python27/bin/ipython /usr/local/bin/ipython;
EXPOSE 8000
EXPOSE 8081

构建本层的镜像Dockerfile中不能指定新的应用进程,否则基本镜像中的sshd就会失效


构建开箱即用的SaaS层镜像(容器启动之后即可提供相应的服务。比如nginx,sshd等)

首先使用base镜像构建一层的supervisord基本镜像

由于supervisord是有python写的,所以可以直接在python模块包中使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
FROM centos6.8-base
MAINTAINER biaoge
ENV LANG=zh_CN.UTF-8;\
LC_ALL=zh_CN.UTF-8;\
TZ=”Asia/Shanghai”;\
TERM=xterm
ADD python27 /usr/local/python27
RUN ln -s /usr/local/python27/bin/python2.7 /usr/local/bin/python27 ;\
ln -s /usr/local/python27/bin/pip /usr/local/bin/pip;\
ln -s /usr/local/python27/bin/ipython /usr/local/bin/ipython;\
ln -s /usr/local/python27/bin/supervisord /usr/local/bin/supervisord;
ADD supervisord.conf /etc/supervisord.conf
EXPOSE 8000 8001
CMD [“/usr/local/bin/supervisord”,”-c”,”/etc/supervisord.conf”]
#这里其实比较建议使用ENTRYPOINT
#ENTRYPOINT通常情况下和CMD会一起使用,区别是CMD定义的执行命令会被container创建的时候的command取代。一般情况下ENTRYPOINT会定义命令执行的主体,CMD中增加默认的参数,而实际的参数可以通过创建container的时候用command进行优化选择
#ENTRYPOINT [“/usr/local/bin/supervisord”,”-c”,”/etc/supervisord.conf”]
#文末会有演示一个ENTRYPOINT的例子

启动之后就会默认启动supervisord.conf中配的服务。

默认的supervisord.conf文件配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
[supervisord]
http_port=/var/tmp/supervisor.sock ; (default is to run a UNIX domain socket server)
logfile=/var/log/supervisord.log ; (main log file;default $CWD/supervisord.log)
logfile_maxbytes=50MB ; (max main logfile bytes b4 rotation;default 50MB)
logfile_backups=10 ; (num of main logfile rotation backups;default 10)
loglevel=info ; (logging level;default info; others: debug,warn)
pidfile=/var/run/supervisord.pid ; (supervisord pidfile;default supervisord.pid)
nodaemon=true ; (start in foreground if true;default false)
minfds=1024 ; (min. avail startup file descriptors;default 1024)
minprocs=200 ; (min. avail process descriptors;default 200)
[supervisorctl]
serverurl=unix:///var/tmp/supervisor.sock ; use a unix:// URL for a unix socket
#额外管理的服务
#[program:httpd]
#command = /usr/sbin/httpd
#[program:sshd]
#command = /usr/sbin/sshd -D

使用上面构建的supervisord镜像进行构建服务镜像

镜像可自启动包含sshd和rabbitmq的服务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
FROM supversord
MAINTAINER biaoge
#需要如下相关的包
#esl-erlang_18.1-1~centos~6_amd64.rpm esl-erlang-compat-18.1-1.noarch.rpm rabbitmq-server-3.1.5-1.noarch.rpm
COPY *.rpm /usr/local/
RUN yum localinstall /usr/local/*.rpm -y
RUN ssh-keygen -q -N “” -t dsa -f /etc/ssh/ssh_host_dsa_key ;\
ssh-keygen -q -N “” -t rsa -f /etc/ssh/ssh_host_rsa_key ;\
sed -ri ‘s/session required pam_loginuid.so/#session required pam_loginuid.so/g’ /etc/pam.d/sshd ;\
mkdir -p /root/.ssh && chown root.root /root && chmod 700 /root/.ssh ;\
sed -ri ‘s/#Port 22/Port 52568/g’ /etc/ssh/sshd_config ;\
echo ‘root:redhat’ | chpasswd
EXPOSE 52568 5672 4369
#这里只需要将更新的配置文件拷贝进去,最终会继承父进程中的CMD去执行supervisord中定义的服务
ADD supervisord.conf /etc/supervisord.conf

用来启动sshd和rabbitmq服务的supervisord.conf配置文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
[supervisord]
http_port=/var/tmp/supervisor.sock ; (default is to run a UNIX domain socket server)
logfile=/var/log/supervisord.log ; (main log file;default $CWD/supervisord.log)
logfile_maxbytes=50MB ; (max main logfile bytes b4 rotation;default 50MB)
logfile_backups=10 ; (num of main logfile rotation backups;default 10)
loglevel=info ; (logging level;default info; others: debug,warn)
pidfile=/var/run/supervisord.pid ; (supervisord pidfile;default supervisord.pid)
nodaemon=true ; (start in foreground if true;default false)
minfds=1024 ; (min. avail startup file descriptors;default 1024)
minprocs=200 ; (min. avail process descriptors;default 200)
[supervisorctl]
serverurl=unix:///var/tmp/supervisor.sock ; use a unix:// URL for a unix socket
#额外管理的服务
[program:rabbitmq]
command = rabbitmq-server
[program:sshd]
command = /usr/sbin/sshd -D

测试访问:
使用上面Dockerfile创建images进行构建容器:

$docker run -itd –name test-ssh sshd-rabbitmq

发现创建的容器,已经通过上面的supervisord.conf中定义好的,启动了rabbitmq和sshd服务。

构建基于PaaS层的其他基本镜像

基本sshd镜像:

1
2
3
4
5
6
7
8
9
10
11
12
13
FROM supervisord
MAINTAINER 371990778@qq.com
#配置相关的ssh需要的文件,以及相关的用户密码
RUN ssh-keygen -q -N “” -t dsa -f /etc/ssh/ssh_host_dsa_key ;\
ssh-keygen -q -N “” -t rsa -f /etc/ssh/ssh_host_rsa_key ;\
sed -ri ‘s/session required pam_loginuid.so/#session required pam_loginuid.so/g’ /etc/pam.d/sshd ;\
mkdir -p /root/.ssh && chown root.root /root && chmod 700 /root/.ssh ;\
sed -ri ‘s/#Port 22/Port 52568/g’ /etc/ssh/sshd_config ;\
echo ‘root:redhat’ | chpasswd
EXPOSE 52568
#这里只需要将更新的配置文件拷贝进去,最终会继承父进程中的CMD去执行supervisord中定义的服务
ADD supervisord.conf /etc/supervisord.conf

相应的supervisord.conf文件中只需要增加相应的额服务启动命令

基本redis镜像:

1
2
3
4
5
6
7
8
9
10
11
FROM sshd-base
MAINTAINER biaoge
ADD redis-2.8.9 /usr/local/redis-2.8.9
#ADD redis.conf /etc/redis.conf
RUN ln -s /usr/local/redis-2.8.9/src/redis-cli /usr/local/bin/redis-cli ;\
ln -s /usr/local/redis-2.8.9/src/redis-server /usr/local/bin/redis-server;\
ln -s /usr/local/redis-2.8.9/redisd.sh /usr/local/bin/redisd.sh
EXPOSE 3679
ADD supervisord.conf /etc/supervisord.conf
#CMD /usr/local/bin/redis-server

基本rabbit镜像:

1
2
3
4
5
6
7
8
9
10
11
FROM sshd-base
MAINTAINER biaoge
#需要如下相关的包
#esl-erlang_18.1-1~centos~6_amd64.rpm esl-erlang-compat-18.1-1.noarch.rpm rabbitmq-server-3.1.5-1.noarch.rpm
COPY *.rpm /usr/local/
RUN yum localinstall /usr/local/*.rpm -y
EXPOSE 5672 4369
#这里只需要将更新的配置文件拷贝进去,最终会继承父进程中的CMD去执行supervisord中定义的服务
ADD supervisord.conf /etc/supervisord.conf

其他案例示范:

1
2
3
4
5
6
7
8
9
FROM centos:6.8
MAINTAINER “Andy_xu”
ENV TZ “Asia/Shanghai”
#ENV PATH $PATH:/export/data/
ENV TERM xterm
RUN mkdir -p /export/package
COPY * /export/package

 

注意:上面dockerfile文件构建的环境没有默认的ps,需要加载export PS1='[\u@\h \W]\$'

ENTRYPOINT 指令详解

发表评论

电子邮件地址不会被公开。 必填项已用*标注