七、Dockerfile
于2021年10月1日更新
一、简介
Dockerfile是一个文本格式的脚本文件,用来快速创建自定义的镜像。
二、指令的两种格式
1)shell格式
RUN <命令行命令>
<命令行命令> 等同于,在终端操作的 shell 命令。
RUN echo "hello world!"
2)exec格式(推荐使用)
RUN ["可执行文件", "参数1", "参数2"]
RUN ["./test.php", "dev", "offline"]
#等同于shell格式
RUN ./test.php dev offline
三、常用指令
FROM
指定基础镜像,我们定制的镜像都是基于基础镜像。
语法:
FROM <image>
FROM <image>:<tag>
FROM <image>:<digest>
:'
三种写法,其中<tag>和<digest> 是可选项,如果没有选择,那么默认值为latest
'
案例:
FROM centos
FROM centos:latest
我们下载的镜像,99%都是基于scratch镜像。
MAINTAINER
指定作者信息
语法:
MAINTAINER <name>
案例:
MAINTAINER tz
MAINTAINER tz<123456@qq.com>
COPY
复制命令
语法:
COPY <src>... <dest>
COPY ["<src>",... "<dest>"]
案例:
COPY hom* /mydir/
COPY ["home.txt","/mydir/"]
ADD
也是复制命令
在执行
语法:
ADD <src>... <dest>
ADD ["<src>",... "<dest>"]
案例:
ADD home.tar /mydir/
ADD ["https://xxx.com/home.tar","/mydir/"]
ENY
设置环境变量,变量可被后续的run指令使用,在镜像启动的容器中也会存在。
语法:
ENV <key>
ENV <key>=<value>
案例:
ENV APP_VERSION=1.0.0
ENV APP_HOME=/usr/local/app
EVN PATH $PATH:/usr/local/bin
EXPOSE
声明容器服务端口
注意:仅仅是声明,并不会做端口映射,端口映射还需要配合docker run -p使用
在运行时使用随机端口映射时,也就是 docker run -P 时,会自动随机映射 EXPOSE 的端口。
语法:
EXPOSE <端口1> [<端口2>...]
案例:
EXPOSE 80
VOLUME
定义匿名挂载数据卷。
在启动容器时忘记使用-v挂载数据卷,会自动挂载该匿名卷。
语法:
VOLUME ["<路径1>", "<路径2>"...]
VOLUME <路径>
案例:
VOLUME ["/var/log/"]
VOLUME /var/log
VOLUME /var/log /var/db
在启动容器 docker run 的时候,我们可以通过 -v 参数修改挂载点。
WORKDIR
指定工作目录,必须是提前创建好的
语法:
WORKDIR <工作目录路径>
案例:
WORKDIR /usr/local/
RUN
运行容器时指定的命令
常用来在当前镜像基础上执行指定命令
语法:
RUN <command>
RUN ["executable", "param1", "param2"]
案例:
#格式一
RUN yum -y install vim\
&& yum -y install httpd
#格式二
RUN ["/bin/bash", "-c", "echo hello tz"]
注意:多行命令不要写多个RUN,原因是Dockerfile中每一个指令都会建立一层镜像,多少个RUN就构建了多少层镜像,会造成镜像的臃肿、多层,同时还增加了构件部署的时间。
CMD
容器启动时要运行的命令
该命令会在容器启动且docker run没有指定其他命令时运行
如果指定了多条命令,只有最后一条会被执行
会被docker run命令行参数指定的指令所覆盖
语法:
CMD command param1 param2
CMD ["executable","param1","param2"]
CMD ["param1","param2"]
案例:
CMD echo "hello tz"
CMD [ "sh", "-c", "echo $HOME" ]
CMD [ "echo", "$HOME" ]
ENTRYPOINT
类似于 CMD 指令,但其不会被 docker run 的命令行参数指定的指令所覆盖。
docker run命令行参数会被当作参数送给 ENTRYPOINT 指令
如果 Dockerfile 中如果存在多个 ENTRYPOINT 指令,仅最后一个生效。
语法:
ENTRYPOINT ["<executeable>","<param1>","<param2>",...]
案例:
#构建nginx:test镜像
vim Dockerfile
FROM nginx
ENTRYPOINT ["nginx", "-c"] # 定参
CMD ["/etc/nginx/nginx.conf"] # 变参
#不传参数运行
docker run nginx:test
:'
不传参数运行解释
docker run不传参数运行,CMD命令就会当作docker run的参数执行,但是因为指定了ENTRYPOINT指令,故CMD命令会被当成参数传给 ENTRYPOINT 指令
最后相当于执行了`docker run --name n1 nginx -c /etc/nginx/nginx.conf`语句。
'
#传参数运行
docker run nginx:test -c /etc/nginx/new.conf
#nginx -c /etc/nginx/new.conf
:'
传参数运行解释
docker run传参数运行,CMD命令就会被覆盖,docker run的命令行参数会被带入ENTRYPOINT指令,结果就相当于执行了nginx -c /etc/nginx/new.conf
'
LABEL
给生成的镜像添加一些元数据标签信息,这些信息可以用来辅助过滤出特定的镜像。
格式为键值对的形式。
语法:
LABEL <key>=<value> <key>=<value> <key>=<value> ...
案例:
LABEL author="tz" \
version="1.0" \
description="xxxxxx"
Build
构建镜像指令
语法:
ocker build -t nginx:v3 .
:'
-t: 构建的镜像名加标签
注意最后那个点,表示上下文
镜像构建过程是在docker引擎下完成的,无法用到宿主机文件,这时需要使用上下文将Dockerfile 所在的位置打包发送给docker引擎。
'
其他选项解释
-t, --tag list # 镜像名称
-f, --file string # 指定Dockerfile文件位置
- #表示通过STDIN给出Dockerfile或上下文
:'
示例
docker build . # 默认找当前目录以Dockerfile为命名的文件
docker build -t shykes/myapp .
docker build -t shykes/myapp -f /path/Dockerfile .
docker build -t shykes/myapp - < Dockerfile
docker build -t shykes/myapp - < context.tar.gz
docker build -t shykes/myapp http://www.example.com/Dockerfile
docker build -f shykes/myapp http://www.example.com/contex.tar.gz
'
可参考:build命令详解,build命令详解2
四、命令总结
4.1 常用指令速记图
4.2 RUN 、CMD 和 ENTRYPOINT 指令区别
- RUN在构建镜像时运行,可以写多条,常用于安装软件包。
- CMD和ENTRYPOINT在运行容器时运行,只能写一条,如果写多条,最后一条生效。
- CMD会被docker run命令行参数指定的指令所覆覆盖,ENTRYPOINT不会被覆盖,但可以指定--entrypoint被覆盖。
四、案例
4.1 构建PHP网站镜像
因为centos6已经停止更新了,yum源大多已失效,这个案例已经无法实现其功能,写在这里了解Dockerfile使用即可。
1)创建上下文目录
mkdir /root/docker
cd /root/docker
2)编辑Dockerfile文件
vim Dockerfile #必须以Dockerfile命名
#基础镜像来源自centos:latest
FROM sglim2/centos7
#维护者信息
MAINTAINER tz
#配置阿里源
RUN yum -y install wget\
&& wget -O /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-6.repo
#构建镜像时运行的shell命令
RUN yum install -y httpd php php-gd php-mysql mysql mysql-server
#设置容器环境变量即mysql密码
ENV MYSQL_ROOT_PASSWORD 123456
RUN echo "<?php phpinfo()?>" > /var/www/html/index.php
#拷贝脚本到镜像根目录下
ADD start.sh /start.sh
RUN chmod +x /start.sh
ADD https://cn.wordpress.org/wordpress-4.7.4-zh_CN.tar.gz /var/www/html
COPY wp-config.php /var/www/html/wordpress
#将容器指定目录如mysql数据库目录挂载到宿主机自动生成的目录
VOLUME ["/var/lib/mysql"]
CMD /start.sh
#申明容器运行开放的端口
EXPOSE 80 3306
3)编辑start.sh脚本
vim start.sh
service httpd start
service mysqld start
mysqladmin -uroot password $MYSQL_ROOT_PASSWORD
#使用如下命令使容器一直运行,容器是linux的一个进程如果没有持续运行的事务就会退出
tail -f
4)使用build构建镜像
docker build -t wordpress:v1 .
5)通过构建的镜像创建容器
docker run -itd --name wordpress -p 80:80 wordpress:v1
6)验证
文件也拷贝进去了
docker exec wordpress ls /var/www/html
index.php
wordpress
访问拷贝进去的wordpress博客,自己动手安装
http://宿主机ip:80/wordpress/
登录容器里的数据库
容器中$mysql -uroot -p$MYSQL_ROOT_PASSWORD
目前centos6已经停止更新了,网上的yum源也大多已经失效,这里有一个可以用的。
4.2 构建JAVA网站镜像
1)创建上下文目录,上传jdk-8u221-linux-x64.tar.gz跟apache-tomcat-8.5.71.tar.gz到该目录下
mkdir /root/docker
cd /root/docker
2)编写Dcokerfile文件
vim Dockerfile
FROM centos:6
MAINTAINER tz
ADD jdk-8u221-linux-x64.tar.gz /usr/local
ENV JAVA_HOME /usr/local/jdk1.8.0_221
ADD apache-tomcat-8.5.71.tar.gz /usr/local
WORKDIR /usr/local/apache-tomcat-8.5.71
ENTRYPOINT ["bin/catalina.sh", "run"]
EXPOSE 8080
3)使用build构建镜像
-f指定上下文路径
docker build -t tomcat:v1 -f /root/docker/Dockerfile .
4)通过构建的镜像创建容器
docker run -itd --name tomcat -p 8080:8080 tomcat:v1
如果创建失败及时查看日志找原因
docker logs tomcat
4.3 构建SSH服务镜像
1)创建上下文目录
mkdir /root/docker
cd /root/docker
2)编辑Dockerfile文件
vim Dockerfile
FROM sglim2/centos7
MAINTAINER tz
ENV ROOT_PASSWORD 123456
RUN yum install -y openssh-server && yum -y install passwd
RUN echo $ROOT_PASSWORD |passwd --stdin root
RUN ssh-keygen -t dsa -f /etc/ssh/ssh_host_dsa_key
RUN ssh-keygen -t rsa -f /etc/ssh/ssh_host_rsa_key
CMD ["/usr/sbin/sshd", "-D"]
EXPOSE 22
3)使用build构建镜像
docker build -t ssh:v1 .
4)通过构建的镜像创建容器
docker run -itd --name ssh -p 2222:22 ssh:v1
5)验证
ssh 10.154.0.110 2222
五、附录
5.1 FROM指令补充
登录dockerhub搜索centos镜像,点击如下
可以看到centos镜像是基于FROM镜像创建的
六、参考资料
《每天5分钟玩转docker容器》第三章
《docker技术入门与实战》第八章