1 Dockerfile 指令介绍
- FROM 这个镜像的妈妈是谁?(指定基础镜像)
- MAINTAINER 告诉别人,谁复制养它(指定维护者信息,可以没有)
- RUN 你想让它干啥(在命令前面加上 RUN 即可)
- ADD 添加宿主机的文件到容器里,还多了一个自动解压的功能
- COPY 作用和ADD是一样的,都是拷贝宿主机的文件到容器内,COPY 就是仅仅拷贝
- WORKDIR 我是cd,今天刚化了妆(设置当前工作目录)
- VOLUME 给它一个存放行李的地方(设置卷,挂载主机目录)
- EXPOSE 它要打开的门是啥(指定对外的端口)
- CMD 奔跑吧,兄弟!(指定容器启动后要干的事情)
- ENV 环境变量
- ENTRYPOINT 容器启动后执行的命令
2 使用 Dockerfile 构建镜像
- 写一个 dockerfile 构建一个 nginx 镜像,运行生成容器后,并且对 nginx 的首页内容进行更改
# 创建 Dockerfile,注意文件名,必须是 Dockerfile,内容如下
FROM nginx
RUN echo '<meta charset=utf8> tfos 带你用 docker 运行 nginx 服务.' > /usr/share/nginx/html/index.html
# 在 Dockerfile 文件目录下构建镜像,. 表示当前目录
docker build .
# 查看镜像
docker images
# 修改镜像名
docker tag 镜像id 修改后的镜像名
# 运行该镜像,生成容器
docker run -d -p 80:80 镜像名称
# 查看当前运行的容器
docker ps
- 访问宿主机的 80 端口
2 COPY 指令
- copy 指令从宿主机复制文件/目录到新的一层镜像内,copy 指令能够保留源文件的元数据,如权限,访问时间等等,这点很重要
# 复制宿主机文件到镜像内指定的目录
copy 宿主机文件 镜像目录
# 支持多个文件,以及通配符形式复制,语法要满足 Golang 的 filepath.Match
copy 文件名* /tmp/tfos?.tex. /home
3 ADD 指令
- 特性和 COPY 基本一致,不过多了些功能
- 源文件是一个 URL,此时 docker 引擎会下载该链接,放入目标路径,且权限自动设为 600,若这不是期望结果,还得增加一层 RUN 指令进行调整
- 源文件是一个 URL,且是一个压缩包,不会自动解压,也得单独用 RUN 指令解压
- 源文件是一个压缩文件,且是 gzip,bzip2,xz,tar 情况,ADD 指令会自动解压缩该文件到目标路径
- Dockerfile 官方更为推荐使用 COPY,ADD 包含了更多复杂的功能,且 ADD 会使构建缓存失效,导致镜像构建缓慢
4 CMD 指令
- 用法,注意是双引号,在指定了 entrypoint 指令后,用 CMD 指定具体的参数
CMD ["参数1","参数2"]
- docker 不是虚拟机,容器就是一个进程,既然是进程,那么程序在启动的时候需要指定些运行参数,这就是 CMD 指令
- 例如 centos 镜像默认的 CMD 是 /bin/bash,直接 docker run -it centos 会直接进入 bash 解析器,等同于:CMD ["/bin/bash"]
- 也可以启动容器时候,指定参数,docker run -it centos cat /etc/os-release,等同于:CMD ["cat","/etc/os-release"]
- CMD 指令 shell 命令,也会被转化为 shell 形式,例如 CMD echo $PATH 会被转换为 CMD ["sh","-c","echo $PATH"]
5 容器内运行程序
- 这里要注意的是,docker 不是虚拟机的概念,虚拟机里的程序运行,基本上都是在后台运行,利用 systemctl 运行,但是容器内没有后台进程的概念,必须在前台运行
- 容器就是为了主进程而存在的,主进程如果退出了,容器也就丢失意义,自动退出
- 例如有一个经典问题
- CMD systemctl start nginx,这样的写法是错误的,容器会立即退出
- 因为 systemctl start nginx 是希望以守护进程形式启动 nginx,且 CMD 命令会转换为:CMD ["sh","-c","systemctl start nginx"]
- 这样的命令主进程是 sh 解析器,执行完毕后立即结束了,因此容器也就退出了
- 因此正确的做法应该是 CMD ["nginx","-g","daemon off;"]
6 ENTRYPOINT 指令
- 和 RUN 指令一样,分为两种格式:exec 和 shell
- 作用和 CMD 一样,都是在指定容器启动程序以及参数
- 当指定了 ENTRYPOINT 之后,CMD 指令的语义就有了变化,而是把 CMD 的内容当作参数传递给 ENTRYPOINT 指令
- 实际用法
- 准备好 Dockerfile
FROM centos:7.8.2003
RUN rpm --rebuilddb && yum install epel-release -y
RUN rpm --rebuilddb && yum install curl -y
CMD ["curl","-s","http://ipinfo.io/ip"]
- 构建镜像
docker build .
- 查看镜像
docker images
- 修改镜像名称
docker tag 镜像id 修改后的镜像名称
- 根据名字查找镜像
docker images | grep 修改后的镜像名称
- 运行镜像,生成容器实例,没有前台运行,因此立即挂了
docker run 修改后的镜像名称
- 上述运行正确,但是我想再传入一个参数,该怎么操作?发现是无法直接传入参数的,该形式是覆盖镜像中的 CMD,就好比把该 docker 镜像当作一个环境去执行后的命令
- 想要争取的给容器传入一个 -I 参数,该怎样操作?
- 解决办法1,导致镜像没有意义
docker run 修改后的镜像名称 curl -s http://ipinfo.io/ip -I
- 解决办法2,使用 ENTRYPOINT
# 修改 Dockerfile如下
FROM centos:7.8.2003
RUN rpm --rebuilddb && yum install epel-release -y
RUN rpm --rebuilddb && yum install curl -y
ENTRYPOINT ["curl","-s","http://ipinfo.io/ip"]
# 重新构建镜像
docker build .
# -t 指定构建镜像 tag 名称
docker build -t '镜像名称' .
# --no-cache 构建时不使用旧的缓存,重新下载生成新的缓存
docker build --no-cache -t '镜像名称' .
# 查看本机所有镜像
docker images
# 重新修改镜像名称
docker tag 镜像id 新的镜像名称
# 根据镜像名称查找镜像
docker images | grep 修改后的镜像名称
# 重新运行镜像,生成容器,传入的 CMD 参数作为 ENTRYPOINT 的参数来执行
docker run 新的镜像名称 -I
7 ARG 和 ENV 命令
- ENV 设置环境变量,后续所有的操作,通过 $变量名 就可以直接获取变量值绑定了,维护 dockerfile 脚本时更友好方便
- ARG 和 EVN 一样,都是设置环境变量,区别在于 EVN 无论是在镜像构建,还是容器运行,该变量都可以使用;ARG 只是用于构建镜像需要设置的变量,容器运行时就消失了
ENV NAME="tfos"
ENV AGE="18"
ENV MYSQL_VERSION=8.0
8 VOLUME 指令
- 容器在运行时,应该保证在存储层不写入任何数据,运行在容器内生产的数据,我们推荐是挂载,写入到宿主机上,进行维护
# 将容器内的 /data 文件夹,在容器运行时,该目录自动挂载为匿名卷,任何向该目录中写入数据的操作,都不会被容器记录,保证的容器存储层无状态理念
VOLUME /data # Dockerfile 样例
FROM centos:7.8.2003
MAINTAINER tfos
VOLUME ["/data1","data2"]
# 该容器运行时,这两个目录自动和宿主机目录做好映射关系
docker build .
docker run 镜像id
docker inspect 镜像id
- 容器数据挂载的方式,通过 dockerfile,指定 VOLUME 目录
- 通过 docker run -v 参数,直接设置需要映射挂载的目录
9 EXPOSE 指令
- 指定容器运行时对外提供的端口服务
- 帮助使用该镜像的人,快速理解该容器的一个端口业务
docker port 容器
docker run -p 宿主机端口:容器端口
# -P 随机宿主机端口:容器端口
docker run -P
10 WORKDIR 指令
- 用于在 dockerfile 中,目录的切换,更改工作目录
WORKDIR /opt
11 USER 指令
- 用于改变环境,用于切换用户
USER root