layout: post
title: 构建可执行程序的Dockerfile
date: 2018-04-15
tags: [“Docker”,”自动化运维工具”]
1、RUN指令
用于指定docker build过程中运行的程序,其可以是任何命令,而且可以使用多次
Syntax
1、RUN
2、RUN [“
基于第一种格式的,SIGTERM
和 SIGKILL
);
基于第二种语法格式中的参数是一个JSON格式的数组,其中RUN ["/bin/bash","-c","<executable>","<param1>"]
2、CMD指令
用于在启动容器运行容器应用的,当有多个CMD的时候,仅最后一个会生效。
Syntax:
CMD <command> #同RUN
CMD ['<executable>','<param1>','<param2>'] #同RUN
CMD ['param1','param2'] #用于ENTRYPOINT指令提供默认参数
简单示例:
- [root@ansible_master file_02]# vim Dockerfile
- FROM busybox:latest
- LABEL maintainer="zhangshang
" #ADD index.html /data/web/html RUN mkdir -p /data/web/html \ && echo 'test RUN and CMD !' >/data/web/html/index.html EXPOSE 80/tcp CMD httpd -h /data/web/html -f
构建镜像
- [root@ansible_master file_02]# docker build . -t http:test1
- Sending build context to Docker daemon 3.072kB
- Step 1/5 : FROM busybox:latest
- ---> 8ac48589692a
- Step 2/5 : LABEL maintainer="zhangshang
" ---> Using cache ---> 7cee9591fed5 Step 3/5 : RUN mkdir -p /data/web/html && echo 'test RUN and CMD !' >/data/web/html/index.html ---> Running in e8b355a82e1d Removing intermediate container e8b355a82e1d ---> a83e40806db2 Step 4/5 : EXPOSE 80/tcp ---> Running in 17d9bb504bb6 Removing intermediate container 17d9bb504bb6 ---> ac8ac81d7d84 Step 5/5 : CMD httpd -h /data/web/html -f ---> Running in 64db8ba82a0c Removing intermediate container 64db8ba82a0c ---> 7106ff92352c Successfully built 7106ff92352c Successfully tagged http:test1
运行容器
- [root@ansible_master file_02]# docker run -itd --rm --name test2 http:test1
- 4fd41b3ab75560160dfca075d4183821c4f64334118e7d1db9aa19205058ab78
- [root@ansible_master file_02]# curl 172.17.0.3
- test RUN and CMD !
使用CMD最为默认执行程序是可以被覆盖掉的
3、ENTRYPOINT指令 与CMD指令相同,唯一的不同点,在运行使用ENTRYPOINT指令构建的镜像生成的容器默认执行程序不会被覆盖。所以我们一般使用ENTRYPOINT来构建镜像,只使用CMD指令来为ENTRYPOINT传递参数。所以上一个实例应该写成如下形式。
- [root@ansible_master file_02]# docker run -itd --rm --name test2 http:test1 /bin/sh
- a863fbcc5c2f8f00476304c1cdb0493505c908657a4f4e2010701a3c19f24e26
- [root@ansible_master file_02]# curl 172.17.0.3
- curl: (7) Failed connect to 172.17.0.3:80; 拒绝连接
- 以上启动的容器被/bin/sh覆盖了
- [root@ansible_master file_02]# vim Dockerfile
- FROM busybox:latest
- LABEL maintainer="zhangshang
" #ADD index.html /data/web/html RUN mkdir -p /data/web/html \ && echo 'test RUN and CMD !' >/data/web/html/index.html EXPOSE 80/tcp CMD ["httpd","-h","/data/web/html","-f"] ENTRYPOINT ["/bin/sh","-c"] #容器运行会直接退出,因为父进程是"sh",而httpd是子进程,父进程是在后台运行的,可以使用exec用子进程代替父进程。
或(建议都已非shell的方式运行)
- [root@ansible_master file_02]# vim Dockerfile
- FROM busybox:latest
- LABEL maintainer="zhangshang
" #ADD index.html /data/web/html RUN mkdir -p /data/web/html \ && echo 'test RUN and CMD !' >/data/web/html/index.html EXPOSE 80/tcp CMD ["-h","/data/web/html","-f"] ENTRYPOINT ["httpd"]
CMD与ENTRYPOINT的交互方式
1)Dockerfile应至少指定CMD或ENTRYPOINT命令中的一个。
2)当使用容器作为可执行文件时,应该定义ENTRYPOINT。
3)应该使用CMD作为定义ENTRYPOINT命令的缺省参数或在容器中执行ad-hoc命令的方式。
4)使用替代参数运行容器时,CMD将被覆盖。
下表显示了针对不同的ENTRYPOINT / CMD组合执行的命令:
注意:CMD和ENTRYPOINT混用时,格式不同运行会出问题
通过脚本的方式运行ENTRYPOINT(使用ENTRYPOINT执行脚本,在运行容器时,在脚本内进行环境设定,这才是ENTRYPOINT的正确姿势)
- 编辑脚本
- vim entrypoint.sh
- #! /bin/sh
- if ! id httpd &>/dev/null; then
- adduser httpd
- fi
- exec "$@"
复权
- chmod 755 entrypoint.sh
编辑dockerfile
- [root@ansible_master file_02]# vim Dockerfile
- FROM busybox:latest
- LABEL maintainer="zhangshang
" #ADD index.html /data/web/html RUN mkdir -p /data/web/html \ && echo 'test RUN and CMD !' >/data/web/html/index.html EXPOSE 80/tcp CMD ["httpd","-h","/data/web/html","-f"] ENTRYPOINT ["/bin/entrypoint.sh"]