第三章 : Dockerfile
在空目录中创建 Dockerfile 文本文件 :
vim /dockerfile/nginx/Dockerfile
文件名不一定是 Dockerfile, 可以是其他文件名, 如果使用其他名字必须添加 (-f Dockerfile文件名) 参数
制定镜像 : docker build -t 镜像名:标签 Dockerfile . # 注意命令最后的点 .
1. FROM, USER, WORKDIR
FROM : 指定基础镜像,一个 Dockerfile 中 FROM 是必备的指令,并且必须是第一条指令。
除了选择现有镜像为基础镜像外,Docker 还存在一个特殊的镜像,名为 scratch。这个镜像是虚拟的概念,并不实际存在,它表示一个空白的镜像。
USER : 指定当前用户, 是改变之后层的执行 RUN, CMD 以及 ENTRYPOINT 这类命令的身份, 必须是实现建立好的
WORKDIR : 指定工作目录(或者称为当前目录),以后各层的当前目录就被改为指定的目录,如该目录不存在,WORKDIR 会帮你建立目录。
[root@docker nginx]# cat Dockerfile
FROM a386303138/nginx:v1.20.1
USER nginx
WORKDIR /usr/share/nginx/html
[root@docker nginx]# docker run -it --rm --name nginx_test a386303138/nginx:v1.20.1_with_USER_WORKDIR /bin/bash
nginx@78dd4e0d78e4:/usr/share/nginx/html$ whoami # 查看当前用户
nginx
nginx@78dd4e0d78e4:/usr/share/nginx/html$ pwd # 查看当前目录
/usr/share/nginx/html
2. ADD, EXPOSE
ADD : 更高级的复制文件
ADD 指令和 COPY 的格式和性质基本一致, 复制文件必须在同一目录下
如果 <源路径> 为一个 tar 压缩文件的话,压缩格式为 gzip, bzip2 以及 xz 的情况下,ADD 指令将会自动解压缩这个压缩文件到 <目标路径> 去。
--chown=用户:用户组 改变文件的所属用户及所属组。
EXPOSE : 暴露端口
声明运行时容器提供服务端口,这只是一个声明,在运行时并不会因为这个声明应用就会开启这个端口的服务,
在运行时使用随机端口映射时,也就是 docker run -P 时,会自动随机映射 EXPOSE 的端口。
[root@docker nginx_add_expose]# cat nginx_Dockerfile
FROM a386303138/nginx:v1.20.1
ADD index.html /usr/share/nginx/html/
EXPOSE 80
[root@docker nginx_add_expose]# docker build -t a386303138/nginx:v1.20.1_add_expose -f nginx_Dockerfile .
[root@docker nginx_add_expose]# docker run -itd --rm --name nginx_add -P a386303138/nginx:v1.20.1_add_expose
[root@docker nginx_add_expose]# netstat -luntp # 查看进程
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp6 0 0 :::32768 :::* LISTEN 9490/docker-proxy
[root@docker nginx_add_expose]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
d0fc258e0bbb a386303138/nginx:v1.20.1_add_expose "/docker-entrypoint.…" 5 seconds ago Up 4 seconds 0.0.0.0:32768->80/tcp nginx_add
3. ENV, RUN
ENV : 设置环境变量
格式有两种:
ENV <key> <value>
ENV <key1>=<value1> <key2>=<value2>...
这个指令很简单,就是设置环境变量而已,无论是后面的其它指令,如 RUN,还是运行时的应用,都可以直接使用这里定义的环境变量。
RUN : 执行命令
shell 格式:RUN <命令>,就像直接在命令行中输入的命令一样, 注意要简化命令, 避免多次使用run 并且在最后清理安装包等 [root@docker nginx_env_run]# cat Dockerfile FROM centos:7 ENV VER 9.11.4-26.P2.el7.x86_64 RUN yum install bind-$VER -y [root@docker nginx_env_run]# docker build -t a386303138/nginx_env_run . [root@docker nginx_env_run]# docker run -it --rm a386303138/nginx:v1.20.1_bind_9.11.4_env_run /bin/bash [root@0f161062d9dc /]# printenv # 查看环境变量 VER=9.11.4-26.P2.el7.x86_64 [root@0f161062d9dc /]# rpm -qa bind bind-9.11.4-26.P2.el7.x86_64 # 查看bind软件
4. CMD, ENTRYPOINT
CMD : 容器启动命令
CMD 指令就是用于指定默认的容器主进程的启动命令的, 在运行时可以指定新的命令来替代镜像设置中的这个默认命令
容器 前台 与 后台 应用执行的问题 !!!!
Docker 不是虚拟机,容器中的应用都应该以前台执行,而不是像虚拟机、物理机里面那样,用 systemd 去启动后台服务,容器内没有后台服务的概念。
如果后台启动服务, 容器执行后就会退出, 对于容器而言,其启动程序就是容器应用进程,容器就是为了主进程而存在的,
主进程退出,容器就失去了存在的意义,从而退出,其它辅助进程不是它需要关心的东西。
假设启动nginx服务, 使用 service nginx start 命令,则是希望 upstart 来以后台守护进程形式启动 nginx 服务。
刚才说了 CMD service nginx start 会被理解为 CMD [ "sh", "-c", "service nginx start"],因此主进程实际上是 sh。
那么当 service nginx start 命令结束后,sh 也就结束了,sh 作为主进程退出了,自然就会令容器退出。
正确的做法是直接执行 nginx 可执行文件,并且要求以前台形式运行。比如:
CMD ["nginx", "-g", "daemon off;"]
CMD 指令的格式和 RUN 相似,也是两种格式:
shell 格式:CMD <命令>
exec 格式:CMD ["可执行文件", "参数1", "参数2"...]
参数列表格式:CMD ["参数1", "参数2"...]。在指定了 ENTRYPOINT 指令后,用 CMD 指定具体的参数。
[root@docker nginx_cmd_entrypoint]# cat Dockerfile
FROM centos:7
RUN yum install -y httpd
CMD ["httpd","-D","FOREGROUND"]
[root@docker nginx_cmd_entrypoint]# docker build -t a386303138/httpd:test .
[root@docker nginx_cmd_entrypoint]# docker run -d --rm --name myhttpd -p 83:80 a386303138/httpd:test
[root@docker nginx_cmd_entrypoint]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
944a22c238b5 a386303138/httpd:test "httpd -D FOREGROUND" 4 seconds ago Up 3 seconds 0.0.0.0:83->80/tcp myhttpd
ENTRYPOINT : 入口点
ENTRYPOINT 的格式和 RUN 指令格式一样,分为 exec 格式和 shell 格式。
ENTRYPOINT 的目的和 CMD 一样,都是在指定容器启动程序及参数。ENTRYPOINT 在运行时也可以替代,
不过比 CMD 要略显繁琐,需要通过 docker run 的参数 --entrypoint 来指定。
当指定了 ENTRYPOINT 后,CMD 的含义就发生了改变,不再是直接的运行其命令,而是将 CMD 的内容作为参数传给 ENTRYPOINT 指令
[root@docker ~]# cat /docker/nginx_cmd_entrypoint/Dockerfile
FROM centos:7
ADD entrypoint.sh /entrypoint.sh
RUN yum install -y epel-release -q -y && yum install -y nginx
ENTRYPOINT /entrypoint.sh
[root@docker ~]# cat /docker/nginx_cmd_entrypoint/entrypoint.sh # 创建 entrypoint.sh 脚本文件, 并给予执行权限
#!/bin/bash
/sbin/nginx -g "daemon off;"
chmod a+x entrypoint.sh
[root@docker ~]# docker build -t a386303138/nginx:v1.20.1_with_entrypoint .
[root@docker ~]# docker run --rm --name nginx -p 84:80 a386303138/nginx:v1.20.1_with_entrypoint
# 如果访问不了 index.html, 就进入 nginx 容器的站点目录创建 index.html, 或者在主机创建 index.html 挂载到 nginx 的站点目录中
CMD 与 ENTRYPOINT 区别 :
Dockerfile 中如果使用 CMD 指令, 在 docker run 中添加 shell 的命令会将 CMD 指令取代, 执行 shell 命令
如果使用 ENTRYPOINT 指令, 在 docker run 中添加 shell 的命令不会将 ENTRYPOINT 指令取代, 还是会继续执行 ENTRYPOINT 指令