3.1.1 hello-world——最小的镜像
hello-world是Docker官方提供的一个镜像,用来验证Docker是否安装成功
hello-world的Dockerfile内容如下所示:
只有短短三条指令。
(1) FROM scratch镜像是从白手起家,从0开始构建。
(2) COPY hello/将文件“helo”复制到镜像的根目录。
(3)CMD["hel”容器启动时,执行helo
hello-world虽然是一个完整的镜像,但它并没有什么实际用途。通常来说,我们希望镜像能提供一个基本的操作系统环境,用户可以根据需要安装和配置软件。
输出Hello world
Docker 允许你在容器内运行应用程序, 使用 docker run 命令来在容器内运行一个应用程序。
runoob@runoob:~$ docker run ubuntu:15.10 /bin/echo "Hello world"
Hello world
各个参数解析:
- docker: Docker 的二进制执行文件。
- run: 与前面的 docker 组合来运行一个容器。
- ubuntu:15.10 指定要运行的镜像,Docker 首先从本地主机上查找镜像是否存在,如果不存在,Docker 就会从镜像仓库 Docker Hub 下载公共镜像。
- /bin/echo "Hello world": 在启动的容器里执行的命令
以上命令完整的意思可以解释为:Docker 以 ubuntu15.10 镜像创建一个新容器,然后在容器里执行 bin/echo "Hello world",然后输出结果。
运行交互式的容器
我们通过 docker 的两个参数 -i -t,让 docker 运行的容器实现"对话"的能力:
runoob@runoob:~$ docker run -i -t ubuntu:15.10 /bin/bash
root@0123ce188bd8:/#
各个参数解析:
- -t: 在新容器内指定一个伪终端或终端。
- -i: 允许你对容器内的标准输入 (STDIN) 进行交互。
第二行 root@0123ce188bd8:/#,此时我们已进入一个 ubuntu15.10 系统的容器
cat /proc/version 查看当前系统的版本信息
通过运行 exit 命令或者使用 CTRL+D 来退出容器。
启动容器(后台模式)
使用以下命令创建一个以进程方式运行的容器
runoob@runoob:~$ docker run -d ubuntu:15.10 /bin/sh -c "while true; do echo hello world; sleep 1; done"
2b1b7a428627c51ab8810d541d759f072b4fc75487eed05812646b8534a2fe63
在输出中,我们没有看到期望的 "hello world",而是一串长字符
2b1b7a428627c51ab8810d541d759f072b4fc75487eed05812646b8534a2fe63这个长字符串叫做容器 ID,对每个容器来说都是唯一的,我们可以通过容器 ID 来查看对应的容器发生了什么。
首先,我们需要确认容器有在运行,可以通过 docker ps 来查看:
runoob@runoob:~$ docker ps
CONTAINER ID IMAGE COMMAND ...
5917eac21c36 ubuntu:15.10 "/bin/sh -c 'while t…" ...
输出详情介绍:
- CONTAINER ID: 容器 ID。
- IMAGE: 使用的镜像。
- COMMAND: 启动容器时运行的命令。
- CREATED: 容器的创建时间。
- STATUS: 容器状态。
- 状态有7种:
- created(已创建)
- restarting(重启中)
- running 或 Up(运行中)
- removing(迁移中)
- paused(暂停)
- exited(停止)
- dead(死亡)
- PORTS: 容器的端口信息和使用的连接类型(tcp\udp)。
- NAMES: 自动分配的容器名称。
runoob@runoob:~$ docker logs 2b1b7a428627 #在宿主主机内使用 docker logs 命令,查看容器内的标准输出
启动容器
以下命令使用 ubuntu 镜像启动一个容器,参数为以命令行模式进入该容器:
$ docker run -it ubuntu
查看所有的容器:docker ps -a
启动一个已停止的容器: docker start 容器ID
-d 指定容器的运行模式:docker run -itd --name ubuntu-test ubuntu /bin/bash
此时想要进入容器:docker exec -it 243c32535da7 /bin/bash 如果从这个容器退出,容器不会停止
停止容器:docker stop <容器 ID>
重启容器:systemctl start docker
导出容器:docker export 1e560fca3906 > ubuntu.tar #导出容器 1e560fca3906 快照到本地文件 ubuntu.tar。
导入容器:cat docker/ubuntu.tar | docker import - test/ubuntu:v1 #将快照文件 ubuntu.tar 导入到镜像 test/ubuntu:v1
- 可以通过指定 URL 或者某个目录来导入:
docker import http://example.com/exampleimage.tgz example/imagerepo
删除容器:docker rm -f 1e560fca3906
清理掉所有处于终止状态的容器:docker container prune
删除所有未启动的容器:docker rm $(sudo docker ps -a -q)
杀死所有正在运行的容器:docker kill $(docker ps -a -q)
删除所有镜像:docker rmi $(docker images -q)
强制删除 无法删除的镜像
docker rmi -f <IMAGE_ID>
docker rmi -f $(docker images -q)
查看到容器的端口映射:docker ps
docker port 容器名或ID
查看web日志:docker logs -f beautiful_nash
查看容器内部运行的进程:docker top beautiful_nash
检查 WEB 应用程序: docker inspect beautiful_nash 查看 Docker 的底层信息。它会返回一个 JSON 文件记录着 Docker 容器的配置和状态信息。
查询最后一次创建的容器:docker ps -l
重启正在运行的容器:docker restart beautiful_nash
搜索镜像:docker search httpd
下载镜像:docker pull httpd
使用镜像:docker run httpd
更新镜像:在运行的容器内使用 apt-get update 命令进行更新
列出镜像列表:docker images
- 选项说明:
REPOSITORY | TAG | IMAGE ID | CREATED | SIZE |
镜像的仓库源 | 镜像的标签 | 镜像ID | 镜像创建时间 | 镜像大小 |
- 同一仓库源可以有多个 TAG,代表这个仓库源的不同个版本
- 如果要使用版本为15.10的ubuntu系统镜像来运行容器时,命令如下:
runoob@runoob:~$ docker run -it ubuntu:15.10 /bin/bash
root@d77ccb2e5cca:/#
- 如果你不指定一个镜像的版本标签,例如你只使用 ubuntu,docker 将默认使用 ubuntu:latest 镜像。
删除镜像:docker rmi hello-world
列出本地进行的变更历史:docker history 镜像ID
容器和宿主机之间复制文件
docker cp 文件|目录 容器id:容器路径 #将宿主机的内容拷贝到容器指定路径
docker cp 容器id:容器路径 宿主机目录 #与上相反
数据卷(volume)实现与宿主机共享目录
docker run -v 宿主机路径|任意别名:容器内的路径 镜像名
注意:宿主机路径必须是绝对路径,宿主机目录会覆盖容器内目录内容
如果是别名则会在docker运行容器时自动在宿主机中创建一个目录,并将容器目录文件尖复制到宿主机中
3.1.2 base镜像
base镜像由两层含义:
(1)不依赖其他镜像,从scratch构建
(2)其他镜像可以以他为基础进行扩展
所以,能称作base镜像的通常都是各种 Linux发行版的 Docker镜像,比如 Ubuntu
Debian、 Centos等。
Linux OS由内核空间和用户空间组成
1.rootfs
- 内核空间是 kernel, Linux刚启动时会加载 boots文件系统,之后 boots会被卸载掉。
- 用户空间的文件系统是 rootfs,包含我们熟悉的/dev、/proc、/bin等目录。
- 对于base镜像来说,底层直接用Host的 kernel,自己只需要提供 rootfs就行了。
- 而对于一个精简的OS, rootfs可以很小,只需要包括最基本的命令、工具和程序库就可以。
2.base镜像提供的是最小安装的Linux发行版
注:可在 Docker Hub的镜像描述页面中査看 Dockerfile
3.支持运行多种Linux OS
不同Linux发行版本的区别主要就是rootfs,Linux kernel差别不大。所以Docker可以同时支持多种Linux镜像
(1)base镜像只是在用户空间与发行版一致, kernel版本与发行版是不同的。
例如 Centos7使用3.xx的 kernel,如果 Docker Host是 Ubuntu16.04(比如我们的实
验环境),那么在 Centos容器中使用的实际上是Host 4.1xX的 kernel
① Host kernel为3.10.0
②启动并进入 Centos容器。
③)验证容器是 Centos7.
④容器的 kernel版本与Host一致。
(2)容器只能使用Host的 kernel,并且不能修改。
- 所有容器都共用host的 kernel.,在容器中没办法对 kernel升级。如果容器对 kernel版本有要求(比如应用只能在某个 kernel版本下运行),则不建议用容器,这种场景虚拟机可能更
3.1.3 镜像的分层结构
- 每一个容器运行时,是以镜像为基础层,在其上创建一个当前容器的存储层,我们可以称这个为容器运行时读写而准备的存储层为 容器存储层。
- 容器存储层的生存周期和容器一样,容器消亡时,容器存储层也随之消亡。因此,任何保存于容器存储层的信息都会随容器删除而丢失。
- 有的文件写入操作,都应该使用 数据卷(Volume)、或者 绑定宿主目录,在这些位置的读写会跳过容器存储层,直接对宿主(或网络存储)发生读写,其性能和稳定性更高。
- Docker支持通过扩展现有镜像,创建新的镜像。
- 新镜像是从base镜像一层一层叠加生成的。每安装一个软件,就在现有镜像的
基础上增加一层。
- 为什么 Docker镜像要采用这种分层结构呢?
- 最大的一个好处就是:共享资源。
- 如果多个容器共享一份基础镜像,当某个容器修改了基础镜像的内容,比如/etc下的文件,这时其他容器的etc是否也会被修改?
- 答案是不会!因为修改会被限制在单个容器内。
容器Copy-on-Write特性
当容器启动时,一个新的可写层被加载到镜像的顶部。这一层通常被称作“容器层”,“容器层”之下的都叫“镜像层”
- 所有对容器的改动,无论添加、删除,还是修改文件都只会发生在容器层中。只有容器层是可写的,容器层下面的所有镜像层都是只读的。
- 镜像层数量可能会很多,所有镜像层会联合在一起组成一个统一的文件系统。如果不同层中有一个相同路径的文件,比如a,上层的/a会覆盖下层的/a,也就是说用户只能访问到上层中的文件a。在容器层中,用户看到的是一个叠加之后的文件系统。
(1)添加文件。在容器中创建文件时,新文件被添加到容器层中。
(2)读取文件。在容器中读取某个文件时, Docker会从上往下依次在各镜像层中査找此文件。一旦找到,打开并读入内存
(3)修改文件。在容器中修改已存在的文件时, Docker会从上往下依次在各镜像层中查找此文件。一旦找到,立即将其复制到容器层,然后修改之
(4)删除文件。在容器中删除文件时, Docker也是从上往下依次在镜像层中査找此文件。找到后,会在容器层中记录下此删除操作。
- 只有当需要修改时才复制一份数据,这种特性被称作 Copy-on-Wite。可见,容器层保存的是镜像变化的部分,不会对镜像本身进行任何修改
>>
容器层记录对镜像的修改,所有镜像层都是只读的,不会被容器修改,所以镜像可以被多个容器共享。