赞
踩
所以,能称作 base 镜像的通常都是各种 Linux 发行版的 Docker 镜像,比如 Ubuntu, Debian, CentOS 等。
Linux 操作系统由内核空间和用户空间组成。如下图所示:
内核空间是 kernel,Linux 刚启动时会加载 bootfs 文件系统,之后 bootfs 会被卸载掉。
用户空间的文件系统是 rootfs,包含我们熟悉的 /dev, /proc, /bin 等目录。
对于 base 镜像来说,底层直接用 Host 的 kernel,自己只需要提供 rootfs 就行了。
而对于一个精简的 OS,rootfs 可以很小,只需要包括最基本的命令、工具和程序库就可以了。相比其他 Linux 发行版,CentOS 的 rootfs 已经算臃肿的了,alpine 还不到 10MB。
我们平时安装的 CentOS 除了 rootfs 还会选装很多软件、服务、图形桌面等,需要好几个 GB 就不足为奇了。
base 镜像提供的是最小安装的 Linux 发行版。
不同 Linux 发行版的区别主要就是 rootfs。
比如 Ubuntu 14.04 使用 upstart 管理服务,apt 管理软件包;而 CentOS 7 使用 systemd 和 yum。这些都是用户空间上的区别,Linux kernel 差别不大。
所以 Docker 可以同时支持多种 Linux 镜像,模拟出多种操作系统环境。
上图 Debian 和 BusyBox(一种嵌入式 Linux)上层提供各自的 rootfs,底层共用 Docker Host 的 kernel。
这里需要说明的是:
Docker 镜像要采用这种分层结构呢?最大的一个好处就是 - 共享资源。
如果多个容器共享一份基础镜像,当某个容器修改了基础镜像的内容,比如 /etc 下的文件,这时其他容器的 /etc 是否也会被修改?
当容器启动时,一个新的可写层被加载到镜像的顶部。
这一层通常被称作“容器层”,“容器层”之下的都叫“镜像层”。
所有对容器的改动 - 无论添加、删除、还是修改文件都只会发生在容器层中。
只有容器层是可写的,容器层下面的所有镜像层都是只读的。
镜像层数量可能会很多,所有镜像层会联合在一起组成一个统一的文件系统。如果不同层中有一个相同路径的文件,比如 /a,上层的 /a 会覆盖下层的 /a,也就是说用户只能访问到上层中的文件 /a。在容器层中,用户看到的是一个叠加之后的文件系统。
只有当需要修改时才复制一份数据,这种特性被称作 Copy-on-Write。可见,容器层保存的是镜像变化的部分,不会对镜像本身进行任何修改。
这样就解释了我们前面提出的问题:容器层记录对镜像的修改,所有镜像层都是只读的,不会被容器修改,所以镜像可以被多个容器共享。
不建议用户通过这种方式构建镜像。原因如下:
1、编写Dockerfile文件
FROM node:12-alpine
WORKDIR /Users/cfq/docker/app //表示docker的运行目录(与宿主机的目录是独立的,相当于新建一个虚拟机里的目录)
COPY . . //将dockerfile当前目录下的内容拷贝到docker的workdir
RUN yarn install --production
CMD ["node", "./src/index.js"] //后面的路径是相对于wordir的
2、使用docker build命令构建容器映像。
docker build -t getting-started:1.0 .
3、使用docker run命令启动容器,并指定我们刚刚创建的图像的名称
docker run -dp 3000:3000 getting-started:1.0
如果发现docker起不来,可以使用如下命令查看启动过程
docker run -it -p 3000:3000 getting-started:1.0
也可以用如下方式通过shell进入docker虚拟机进行查看
docker run -it geeting-start:1.0 sh
注意:
指定 base 镜像。
设置镜像的作者,可以是任意字符串。
将文件从 build context 复制到镜像。
COPY 支持两种形式:
COPY src dest
COPY ["src", "dest"]
注意:src 只能指定 build context 中的文件或目录。
与 COPY 类似,从 build context 复制文件到镜像。不同的是,如果 src 是归档文件(tar, zip, tgz, xz 等),文件会被自动解压到 dest。
设置环境变量,环境变量可被后面的指令使用。例如:
...
ENV MY_VERSION 1.3
RUN apt-get install -y mypackage=$MY_VERSION
...
指定容器中的进程会监听某个端口,Docker 可以将该端口暴露出来。我们会在容器网络部分详细讨论。
将文件或目录声明为 volume。我们会在容器存储部分详细讨论。
为后面的 RUN, CMD, ENTRYPOINT, ADD 或 COPY 指令设置镜像中的当前工作目录。
在容器中运行指定的命令。
容器启动时运行指定的命令。
Dockerfile 中可以有多个 CMD 指令,但只有最后一个生效。CMD 可以被 docker run 之后的参数替换。
设置容器启动时运行的命令。
Dockerfile 中可以有多个 ENTRYPOINT 指令,但只有最后一个生效。CMD 或 docker run 之后的参数会被当做参数传递给 ENTRYPOINT。
一个较全的Dockerfile:
# cfq dockerfile
FROM busybox
MAINTAINER cfq
WORKDIR /testdir
RUN touch file1
COPY ["tmpfile2", "."]
ADD ["bunch.tar.gz", "."]
ENV WELCOME "welcome handsome~"
实际上一个特定镜像的名字由两部分组成:repository
和 tag
。
[image name] = [repository]:[tag]
如果执行 docker build 时没有指定 tag,会使用默认值 latest。其效果相当于:
docker build -t ubuntu-with-vi:latest
借鉴软件版本命名方式能够让用户很好地使用镜像。
一个高效的版本命名方案可以让用户清楚地知道当前使用的是哪个镜像,同时还可以保持足够的灵活性。
每个 repository 可以有多个 tag,而多个 tag 可能对应的是同一个镜像。下面通过例子为大家介绍 Docker 社区普遍使用的 tag 方案。
假设我们现在发布了一个镜像 myimage,版本为 v1.9.1。那么我们可以给镜像打上四个 tag:1.9.1、1.9、1 和 latest。
我们可以通过 docker tag 命令方便地给镜像打 tag。
docker tag myimage-v1.9.1 myimage:1
docker tag myimage-v1.9.1 myimage:1.9
docker tag myimage-v1.9.1 myimage:1.9.1
docker tag myimage-v1.9.1 myimage:latest
过了一段时间,我们发布了 v1.9.2。这时可以打上 1.9.2 的 tag,并将 1.9、1 和 latest 从 v1.9.1 移到 v1.9.2。
命令为:
docker tag myimage-v1.9.2 myimage:1
docker tag myimage-v1.9.2 myimage:1.9
docker tag myimage-v1.9.2 myimage:1.9.2
docker tag myimage-v1.9.2 myimage:latest
之后,v2.0.0 发布了。这时可以打上 2.0.0、2.0 和 2 的 tag,并将 latest 移到 v2.0.0。
命令为:
docker tag myimage-v2.0.0 myimage:2
docker tag myimage-v2.0.0 myimage:2.0
docker tag myimage-v2.0.0 myimage:2.0.0
docker tag myimage-v2.0.0 myimage:latest
这种 tag 方案使镜像的版本很直观,用户在选择非常灵活:
https://mp.weixin.qq.com/s/Stoq2hBh4pwX0WXabUY1DQ
https://mp.weixin.qq.com/s/jBY-95LShtfw9Scl5g3Nfg
摘自:CloudMan 向大佬致敬
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。