Skip to content
DAILY QUOTE

“ ”

初始DockerFile

DockerFile就是用来构建docker镜像的构建文件!命令脚本!先体验一下!

通过这个脚本可以生成镜像,镜像是一层一层的,脚本一个个的命令,每个命令都是一层!

bash
#创建一个dockerfile文件,名字可以随便 建议Dockerfile
#文件中的内容: 指令(大写)+参数
$vim dockerfile1   #不支持行内注释
FROM ubuntu #当前这个镜像是以ubuntu为基础的
VOLUME ["volume01","volume02"] #挂载卷的卷目录列表(多个目录)
CMD echo "-----end-----" # 输出一下用于测试
CMD /bin/bash #默认走bash控制台
#这里的每个命令,就是镜像的一层

#构建出这个镜像
docker build -f dockerfile1 -t mystpet/ubuntu . 
-f dockerfile1 找图纸:告诉系统去读名叫 dockerfile1 的文件(而不是默认的 Dockerfile)。 
-t mystpet/ubuntu 贴标签:给造出来的镜像起个名字(-t = tag),斜杠前通常是用户名,后是镜像名。 
. 备材料:把当前目录下的所有文件作为“构建上下文(原材料)”发送给 Docker 引擎。

ubuntu@Mystpet:~$ docker images
                                                                                 i Info   U  In Use
IMAGE                   ID             DISK USAGE   CONTENT SIZE   EXTRA
mystpet/ubuntu:latest   48621b955d22        117MB         29.7MB        
mystpet:lastest         d2ca5f8d1213        667MB          214MB  

#启动自己写的容器镜像
docker run -it 48621b955d22 /bin/bash #运行自己的镜像
ls -l #查看目录

这个卷和外部一定有一个同步的目录!

查看一下卷挂载

docker inspect 容器id
docker inspect 8f3

测试一下刚才的文件是否同步到主机上了!

这种方式我们未来使用的十分多, 因为我们通常会构建自己的镜像!

假设构建镜像时候没有挂载卷,要手动镜像挂载 -v 卷名:容器内路径!

数据卷容器

多个mysql同步数据

bash
# 测试 启动3个容器,通过刚才自己写的镜像启动
# 创建docker01
docker run -it --name docker01 mystpet/ubuntu:latest 

#查看容器docker01内容
root@42db9b1a8946:/# ls
bin   dev  home  lib64  mnt  proc  run   srv  tmp  var       volume02
boot  etc  lib   media  opt  root  sbin  sys  usr  volume01

# 不关闭该容器退出 
CTRL + Q + P

# 创建docker02: 并且让docker02 继承 docker01
ubuntu@Mystpet:~$ docker run -it --name docker02 --volumes-from docker01 mystpet/ubuntu:latest

# 查看容器docker02内容
root@10a8a1e6f3e9:/# ls
bin   dev  home  lib64  mnt  proc  run   srv  tmp  var       volume02
boot  etc  lib   media  opt  root  sbin  sys  usr  volume01

bash
# 再新建一个docker03同样继承docker01
ubuntu@Mystpet:~$ docker run -it --name docker03 --volumes-from docker01 mystpet/ubuntu:latest 

root@548a6c1962dd:/volume01# ls
docker01.txt

# 测试:可以删除docker01,查看一下docker02和docker03是否可以访问这个文件 
# 测试发现:数据依旧保留在docker02和docker03中没有被删除

多个mysql实现数据共享

bash
$ docker run -d -p 3306:3306 -v /home/mysql/conf:/etc/mysql/conf.d -v /home/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 --name mysql01 mysql:5.7 
$ docker run -d -p 3310:3306 -e MYSQL_ROOT_PASSWORD=123456 --name mysql02 --volumes-from mysql01 mysql:5.7 
# 这个时候,可以实现两个容器数据同步!

结论

容器之间配置信息的传递, 数据卷容器的声明周期一直持续到没有容器使用为止。

但是一旦你持久化到了本地,这个时候,本地的数据是不会删除的!

DockerFile

dockerFile是用来构建docker镜像的文件!命令参数脚本!

构建步骤:

1. 编写一个dockerFile文件

2. docker build 构建成为一个镜像

3. docker run 运行镜像

4. docker push 发布镜像(DockerHub、阿里云镜像)

查看婴喜爱官方是怎么做的?

点击后跳到一个Dockerfile

很多官方镜像都像是基础包,很多功能都不具备,我们通常会自己搭建自己的镜像!

官方既然可以制作镜像,能我们一样可以!

Dockerfile的构建过程

基础知识:

  1. 每个保留关键字(指令)都是必须大写字母
  2. 执行从上到下顺序执行
  3. # 表示注释
  4. 每个指令都会创建提交一个新的镜像层,并提交!

dockerFile是面向开发的, 我们以后要发布项目, 做镜像, 就需要编写dockefile文件, 这个文件十分简单!

Docker镜像逐渐成为企业的交互标准,必须要掌握!

步骤:开发,部署, 运维..... 缺一不可!

DockerFile: 构建文件, 定义了一切的步骤,源代码

DockerImages: 通过DockerFile构建生成的镜像, 最终发布和运行的产品!

Docker容器:容器就是镜像运行起来提供服务器

bash
FROM # 基础镜像,一切从这里开始构建 
MAINTAINER # 镜像是谁写的, 姓名+邮箱(新版本Docker采用LABEL,不建议使用MAINTAINER,LABEL author="Socde<stc66@qq.com>") 
RUN # 镜像构建的时候需要运行的命令 
ADD # 步骤,tomcat镜像,这个tomcat压缩包(自动解压)!添加内容 添加同目录 WORKDIR # 镜像的工作目录 
VOLUME # 挂载的目录 
EXPOSE # 保留端口配置(多端口直接空格) 
CMD # 指定这个容器启动的时候要运行的命令,只有最后一个会生效,可被替代 
ENTRYPOINT # 指定这个容器启动的时候要运行的命令,可以追加命令 
ONBUILD # 当构建一个被继承DockerFile这个时候就会运行onbuild的指令,触发指令 
COPY # 类似ADD,将我们文件拷贝到镜像中 ENV # 构建的时候设置环境变量!

Dockerfile指令说明

实战测试

scratch 镜像

bash
FROM scratch ADD centos-7-x86_64-docker.tar.xz / LABEL \ org.label-schema.schema-version="1.0" \ org.label-schema.name="CentOS Base Image" \ org.label-schema.vendor="CentOS" \ org.label-schema.license="GPLv2" \ org.label-schema.build-date="20200504" \ org.opencontainers.image.title="CentOS Base Image" \ org.opencontainers.image.vendor="CentOS" \ org.opencontainers.image.licenses="GPL-2.0-only" \ org.opencontainers.image.created="2020-05-04 00:00:00+01:00" CMD ["/bin/bash"]

Docker Hub 中 99%的镜像都是从这个基础镜像过来的 FROM scratch,然后配置需要的软件和配置来进行构建。

创建一个自己的ubuntu

bash
# 1./home/ubuntu下新建dockerfile目录
mkdir dockerfile
# 2. dockerfile目录下新建mydockerfile-ubuntu文件
vim mydockerfile-ubuntu
# 3.编写Dockerfile配置文件

#基础镜像:明确使用 ubuntu
FROM ubuntu
#维护者信息(使用现代化的 LABEL 语法)
LABEL maintainer="Mystpet<1423322347@qq.com>"
#设置环境变量
ENV MYPATH /usr/local
#设置工作目录(进入容器后默认就在这个目录下)
WORKDIR $MYPATH
#核心逻辑:使用 apt-get 更新源并安装 vim 和 net-tools
# 建议把相关的 RUN 指令用 && 连起来,可以减少镜像的层数(Layer),让镜像体积更小
RUN apt-get update && \
    apt-get install -y vim net-tools
#暴露 80 端口
EXPOSE 80
#容器启动时默认执行的命令(只保留这一个!)
CMD /bin/bash

# 4.通过这个文件构建镜像
# 命令: docker build -f 文件路径 -t 镜像名:[tag] .
$ docker build -f mydockerfile-ubuntu -t myubuntu:0.1 .
-t, --tag: 为构建的镜像指定名称和标签。
-f, --file: 指定 Dockerfile 的路径(默认是 `PATH` 下的 `Dockerfile`

bash
docker images
IMAGE                   ID             DISK USAGE   CONTENT SIZE   EXTRA
myubuntu:0.1            bf30232f7cc8        324MB         94.9MB        

# 6.测试运行
docker run -it myubuntu:0.1 /bin/bash

root@3f22fd8dd934:/usr/local# pwd
/usr/local  # 与Dockerfile文件中 WORKDIR 设置的 MYPATH 一致

docker history 镜像id #查看镜像构建历史步骤

#如果要让CREATED BY 列完整显示,可以加上 --no-trunc 参数。直接在shell中看会比较乱,可以输出到文件查看,就比较直观了 
docker history --no-trunc 镜像:tag

我们平时拿到一个镜像,可以用 “docker history 镜像id” 研究一下是什么做的

CMD 和ENTRYPOINT区别

bash
CMD # 指定这个容器启动的时候要运行的命令,只有最后一个会生效,可被替代。 
ENTRYPOINT # 指定这个容器启动的时候要运行的命令,可以追加命令

CMD:一个随时可以被一脚踢开的“软柿子”(默认建议)

CMD 的本质是给容器提供一个**“默认的建议动作”**。既然是建议,那就是可以商量的,如果你在外面下达了新的指令,它会立刻乖乖让位。

案发现场还原: 假设你的 Dockerfile 是这样写的:

Dockerfile

FROM ubuntu
# 容器启动时,建议执行 ls -l 命令
CMD ["ls", "-l"]
  • 情况 1(听从建议):你直接敲 docker run myubuntu。容器乖乖执行 ls -l,打印出文件列表。

  • 情况 2(强行替代,原形毕露):你敲了 docker run myubuntu /bin/bash。 注意看,你在启动命令的最后加了 /bin/bash。此时,CMD 这个软柿子会被极其无情地整个踢掉(这就是笔记里写的“可被替代”)。容器根本不会执行 ls,而是直接跑去执行 /bin/bash 了。

ENTRYPOINT:宁死不屈的“硬骨头”(绝对铁律)

ENTRYPOINT 的本质是给容器定下**“绝对不能更改的核心使命”。一旦写了它,这个容器生下来就只能干这件事,你在外面敲的任何多余指令,都只能作为参数(小弟)**,乖乖跟在它的屁股后面(这就是笔记里写的“追加命令”)。

案发现场还原: 假设你的 Dockerfile 改成这样:

Dockerfile

FROM ubuntu
# 容器的绝对铁律:生来就是为了 echo(打印字符)的!
ENTRYPOINT ["echo", "hello"]
  • 情况 1(正常执行):你敲 docker run myubuntu。容器打印出 hello

  • 情况 2(强行追加,见证奇迹):你敲了 docker run myubuntu world。 这次,world 根本无法替换掉 echo。Docker 会在底层把 world 当作一个参数,拼接到 ENTRYPOINT 的屁股后面。 实际上底层执行的变成了:echo hello world。最终打印结果是:hello world

Dockerfile中很多命令都十分的相似,我们需要了解它们的区别,我们最好的学习就是对比他们然后测试效果!