# hello-world

要使用那些容器,首先需要拉取镜像到本地仓库,然后再运行

# 拉取 hello-world
docker pull hello-world:latest
# 查看本地仓库的镜像
docker images
# 在容器中运行 hello-world 实例
docker run (--name=XXX) hello-world

拉取指定版本的镜像: docker pull 名称:版本 ,默认是最新版本。run 命令 hi 自动给容器分配名称,也可以使用唯一名称指定。

如果没有调整 docker 的镜像源,那么 docker 就是从 Docker Hub 拉取的镜像到本地仓库。也可直接使用 run 来运行实例,如果本地仓库没有这个实例,那么就会从远端拉取镜像到仓库中。

docker images 的结果有一列是 ID,如果希望删除一个镜像: docker rmi -f <ID>

Docker 允许在容器内运行应用程序: docker run

docker run centos:latest /bin/echo "Hello world"

如果本地仓库没有 centos 的镜像,那么就会先拉取 centos 镜像。看一下参数的含义:

  • docker : Docker 的二进制执行文件。

  • run : 与前面的 docker 组合来运行一个容器。

  • ubuntu:latest 指定要运行的镜像,Docker 首先从本地主机上查找镜像是否存在,如果不存在,Docker 就会从镜像仓库 Docker Hub 下载公共镜像。

  • /bin/echo "Hello world" : 在启动的容器里执行的命令

吐槽:我这拉取 centos 镜像文件好慢。。。

如果我们只是想创建容器而不是去运行

docker create hello-world

如果想要查看所有容器(不论是否运行)

# linux 的 ps 是查看进程
# 不加 - a 就只能查看运行的容器
docker ps -a

想要停止或者删除容器,就需要使用 ID 或者 NAMES 来指定容器,关于容器的相关操作:

  • 删除容器: docker rm <容器名/ID>

  • 停止容器: docker stop <XXX>

  • 运行停止的容器: docker start <XXX> 。因为有些容器是执行完后马上停止,而不是像服务器那样阻塞从而一直保持运行状态。

  • 重启容器: docker restart <XXX>

  • 停止后自动删除: docker run --rm <XXX>

在指定 ID 时,可以不用将 ID 完整打出来,只要前面一部分能够唯一标识该容器即可。

该部分通过 hello-world 的例子讲解了一些命令和容器操作

# 镜像结构

先回顾一下镜像,容器与仓库的关系,这是官网的图:

可以看到,容器的建立(实例化)依赖于镜像,项目打包需要一个基本的操作系统环境,这样才能在操作系统中安装依赖,这种基本的系统镜像,叫做 base 镜像。一般 base 镜像就是各个 Linux 操作系统的发行版。

# 如果你执行过上面的 centos 的 hello world
# 就不需要再执行该语句
docker pull centos

这就是 centos 的 base 镜像,base 镜像省去了内核,内存很小。

# base 镜像机制

Linux 操作系统有内核空间和用户空间组成,这里需要了解两个文件系统:

  • bootfs 包含 BootLoader 和 Linux 内核,在内核启动后,bootfs 会自动卸载。
  • rootfs 包含系统常见目录结构,包括 /dev/bin 等以及一些基本的文件和命令。

base 镜像底层会直接使用宿主主机的内核,而 rootfs 可以在不同容器中运行多种不同的版本,所以实际上 base 镜像只包含 CentOS 的 rootfs。

# uname 查看内核版本
uname -r

因此,Docker 能够同时模拟多种 Linux 操作系统环境。

# 启动 base 镜像
docker run -it centos

参数 -it 进行启动,其中 -i 表示在容器上打开一个标准输入(STDIN)接口, -t 表示分配一个伪 tty 设备,可以支持终端登录(理解为伪终端),一般这两个是一起使用,否则 base 容器启动后就自动停止了。

两个合起来的意思就是会弹出一个可以标准输入的终端提示符。

使用 exit 退出后(CTRL+D 也可以),容器也会停止,再次启动时,需要加上 -i 参数才能输入进行交互,否则就是后台运行

docker start -i <容器ID>

# 安装镜像

前面提到为什么需要一个基本的操作系统,基于 base 镜像,我们可以在这基础上安装各种软件,使用分层结构,每安装一个软件,就在 base 镜像上叠加上去。

** 所有的镜像会叠起来组成一个统一的文件系统,如果不同层中存在相同位置的文件,那么上层的会覆盖掉下层的文件,最终我们看到的是一个叠加之后的文件系统。** 当需要修改容器中的文件时,实际上并不会对镜像进行直接修改,而是在最顶上的容器层(最上面一般称为容器层,下面都是镜像层)进行修改。

各个操作如下:

  • 文件读取:要读取一个文件,Docker 会最上层往下依次寻找,找到后则打开文件。

  • 文件创建和修改:创建新文件会直接添加到容器层中,修改文件会从上往下依次寻找各个镜像中的文件,如果找到,则将其复制到容器层,再进行修改。

  • 删除文件:删除文件也会从上往下依次寻找各个镜像中的文件,一旦找到,并不会直接删除镜像中的文件,而是在容器层标记这个删除操作。

# 参考

https://pdai.tech/md/devops/docker/docker-02-basic.html

https://www.yuque.com/qingkongxiaguang/zwhkpi/kq6rlg#a327ddf2