Docker 入门系列(3)- Docker 容器(创建、启动、终止、进入、删除、导入、导出容器、容器和镜像转化)

简单来说,容器是镜像的一个运行实例。所不同的是,镜像是静态的只读文件,而容器带有运行时需要的可写文件层。

如果认为虚拟机是模拟运行的一整套操作系统(包括内核、应用运行态环境和其他系统环境)和跑在上面的应用,那么 Docker 容器就是独立运行的一个 (或一组)应用,以及它们必需的运行环境。

1. 创建容器

docker create

使用 docker create 命令新建一个容器,新建的容器处于停止状态,可以使用 docker start 命令来启动它。

wohu@iZm5egn5zptnov4j3oxh4fZ:~/docker$ docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                  PORTS               NAMES
33197473a278        hello-world         "/hello"            6 days ago          Exited (0) 6 days ago                       frosty_galileo
wohu@iZm5egn5zptnov4j3oxh4fZ:~/docker$ docker create -it ubuntu:16.04
1f51e44dab220bfffb73bbd27cd7fe08ecf1109d368094329efb1818c32477f3
wohu@iZm5egn5zptnov4j3oxh4fZ:~/docker$ docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                  PORTS               NAMES
1f51e44dab22        ubuntu:16.04        "/bin/bash"         9 seconds ago       Created                                     confident_wu
33197473a278        hello-world         "/hello"            6 days ago          Exited (0) 6 days ago                       frosty_galileo
wohu@iZm5egn5zptnov4j3oxh4fZ:~/docker$ docker start 1f
1f
wohu@iZm5egn5zptnov4j3oxh4fZ:~/docker$ docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                  PORTS               NAMES
1f51e44dab22        ubuntu:16.04        "/bin/bash"         40 seconds ago      Up 2 seconds                                confident_wu
33197473a278        hello-world         "/hello"            6 days ago          Exited (0) 6 days ago                       frosty_galileo

2. 新建并启动容器

docker run

除了创建容器后通过 start 命令来启动,也可以直接新建并启动容器。所需要的命令主要为docker run,等价于先执行 docker create 命令,再执行 docker start 命令。

wohu@iZm5egn5zptnov4j3oxh4fZ:~/docker$ docker run ubuntu:16.04 /bin/echo "hello world"
hello world
wohu@iZm5egn5zptnov4j3oxh4fZ:~/docker$ docker ps -a
CONTAINER ID        IMAGE               COMMAND                  CREATED              STATUS                          PORTS               NAMES
c6813fb16675        ubuntu:16.04        "/bin/echo 'hello wo…"   About a minute ago   Exited (0) About a minute ago                       determined_blackwell
1f51e44dab22        ubuntu:16.04        "/bin/bash"              6 minutes ago        Up 5 minutes                                        confident_wu
33197473a278        hello-world         "/hello"                 6 days ago           Exited (0) 6 days ago                               frosty_galileo
wohu@iZm5egn5zptnov4j3oxh4fZ:~/docker$ 

当利用 docker run 来创建并启动容器时,Docker 在后台运行的标准操作包括:

  • 检查本地是否存在指定的镜像,不存在就从公有仓库下载
  • 利用镜像创建一个容器,并启动该容器
  • 分配一个文件系统给容器,并在只读的镜像层外面挂载一层可读写层
  • 从宿主主机配置的网桥接口中桥接一个虚拟接口到容器中
  • 从网桥的地址池配置一个 IP 地址给容器
  • 执行用户指定的应用程序
  • 执行完毕后容器被自动终止

下面的命令启动一个 bash 终端,允许用户进行交互:

wohu@iZm5egn5zptnov4j3oxh4fZ:~/docker$ docker run -ti ubuntu:16.04 /bin/bash
root@acb806366cf1:/# pwd
/
root@acb806366cf1:/# ls
bin  boot  dev  etc  home  lib  lib64  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var
root@acb806366cf1:/# exit
exit
wohu@iZm5egn5zptnov4j3oxh4fZ:~/docker$ 
  • -t 选项让 Docker 分配一个伪终端 (pseudo-tty) 并绑定到容器的标准输入上
  • -i 则让容器的标准输入保持打开

输入 exit 命令可以退出当前的容器

运行一个容器,使用 docker run 命令即可。 另 docker run -参数 含义:

docker run --name container-name -d image-name
  • --name :为容器起一个名称;
  • -d :detached,执行完这句命令后,控制台将不会阻塞,可以继续输入命令操作,不会阻塞,也就是启动守护式容器,如果执行 docker run --name mycentos -it centos 会进入启动容器的命令控制台,也就是启动交互式容器;
  • -i :以交互方式运行容器,通常与 -t 搭配使用;
  • -t :为容器重新分配一个伪输入终端,通常与 -i 搭配使用;
  • -P:随机端口映射;
  • -p:指定端口映射,后面会有端口映射详细讲解;
  • image-name :要运行的镜像名称;

守护态运行

需要让 Docker 容器在后台以守护态 (Daemonized) 形式运行。此时,可以通过添加 -d 参数来实现。获取容器的输出信息,可以通过 docker logs命令。

wohu@iZm5egn5zptnov4j3oxh4fZ:~/docker$ docker run -d ubuntu:16.04 /bin/echo "this is test output"
89860f528c9a9c4c552ee23837a7254ffcace89a9abf30a1d83e72947341d396
wohu@iZm5egn5zptnov4j3oxh4fZ:~/docker$ docker ps -a
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                      PORTS               NAMES
89860f528c9a        ubuntu:16.04        "/bin/echo 'this is …"   6 seconds ago       Exited (0) 4 seconds ago                        admiring_driscoll
acb806366cf1        ubuntu:16.04        "/bin/bash"              9 minutes ago       Exited (0) 9 minutes ago                        gifted_bartik
c6813fb16675        ubuntu:16.04        "/bin/echo 'hello wo…"   26 minutes ago      Exited (0) 26 minutes ago                       determined_blackwell
1f51e44dab22        ubuntu:16.04        "/bin/bash"              31 minutes ago      Up 31 minutes                                   confident_wu
33197473a278        hello-world         "/hello"                 6 days ago          Exited (0) 6 days ago                           frosty_galileo

wohu@iZm5egn5zptnov4j3oxh4fZ:~/docker$ docker logs 89
this is test output
wohu@iZm5egn5zptnov4j3oxh4fZ:~/docker$ 

3. 终止容器

可以使用 docker stop 来终止一个运行中的容器。该命令的格式为

docker stop [-t|--time[=10]] CONTAINER...

首先向容器发送 SIGTERM 信号,等待一段超时时间 (默认为 10秒) 后,再发送 SIGKILL 信号来终止容器

docker kill 命令会直接发送 SIGKILL 信号来强行终止容器。

此外,当 Docker 容器中指定的应用终结时,容器也会自动终止。例如对于上一节中只启动了一个终端的容器,用户通过 exit 命令或 Ctrl+d 来退出终端时,所创建的容器立刻终止,处于 stopped 状态。

wohu@iZm5egn5zptnov4j3oxh4fZ:~/docker$ docker ps -a
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                      PORTS               NAMES
89860f528c9a        ubuntu:16.04        "/bin/echo 'this is …"   5 minutes ago       Exited (0) 5 minutes ago                        admiring_driscoll
acb806366cf1        ubuntu:16.04        "/bin/bash"              14 minutes ago      Exited (0) 14 minutes ago                       gifted_bartik
c6813fb16675        ubuntu:16.04        "/bin/echo 'hello wo…"   31 minutes ago      Exited (0) 31 minutes ago                       determined_blackwell
1f51e44dab22        ubuntu:16.04        "/bin/bash"              36 minutes ago      Up 36 minutes                                   confident_wu
33197473a278        hello-world         "/hello"                 6 days ago          Exited (0) 6 days ago                           frosty_galileo
wohu@iZm5egn5zptnov4j3oxh4fZ:~/docker$ docker stop 1f
1f
wohu@iZm5egn5zptnov4j3oxh4fZ:~/docker$ docker ps -a
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                      PORTS               NAMES
89860f528c9a        ubuntu:16.04        "/bin/echo 'this is …"   6 minutes ago       Exited (0) 6 minutes ago                        admiring_driscoll
acb806366cf1        ubuntu:16.04        "/bin/bash"              15 minutes ago      Exited (0) 15 minutes ago                       gifted_bartik
c6813fb16675        ubuntu:16.04        "/bin/echo 'hello wo…"   32 minutes ago      Exited (0) 32 minutes ago                       determined_blackwell
1f51e44dab22        ubuntu:16.04        "/bin/bash"              37 minutes ago      Exited (0) 3 seconds ago                        confident_wu
33197473a278        hello-world         "/hello"                 6 days ago          Exited (0) 6 days ago                           frosty_galileo
wohu@iZm5egn5zptnov4j3oxh4fZ:~/docker$ 

处于终止状态的容器,可以通过 docker start 命令来重新启动,docker restart 命令会将一个运行态的容器先终止,然后再重新启动它。

4. 进入容器

docker exec

在使用 -d 参数时,容器启动后会进入后台,用户无法看到容器中的信息,也无法进行操作。使用 docker exec 命令,可以在容器内直接执行任意命令。

wohu@iZm5egn5zptnov4j3oxh4fZ:~/docker$ docker start ac
ac
wohu@iZm5egn5zptnov4j3oxh4fZ:~/docker$ docker ps -a
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                          PORTS               NAMES
89860f528c9a        ubuntu:16.04        "/bin/echo 'this is …"   13 minutes ago      Exited (0) About a minute ago                       admiring_driscoll
acb806366cf1        ubuntu:16.04        "/bin/bash"              22 minutes ago      Up 3 seconds                                        gifted_bartik
c6813fb16675        ubuntu:16.04        "/bin/echo 'hello wo…"   40 minutes ago      Exited (0) 40 minutes ago                           determined_blackwell
1f51e44dab22        ubuntu:16.04        "/bin/bash"              45 minutes ago      Exited (0) 7 minutes ago                            confident_wu
33197473a278        hello-world         "/hello"                 6 days ago          Exited (0) 6 days ago                               frosty_galileo
wohu@iZm5egn5zptnov4j3oxh4fZ:~/docker$ docker exec -ti  ac /bin/bash
root@acb806366cf1:/# ls
bin  boot  dev  etc  home  lib  lib64  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var
root@acb806366cf1:/# exit
exit
wohu@iZm5egn5zptnov4j3oxh4fZ:~/docker$ 

5. 删除容器

docker rm -f|--force[-v|--volumes]CONTAINER[CONTAINER…]

使用 docker rm 命令来删除处于终止或退出状态的容器,主要支持的选项包括:

  • -f,–force=false:是否强行终止并删除一个运行中的容器
  • -l,–link=false:删除容器的连接,但保留容器
  • -v,–volumes=false:删除容器挂载的数据卷

默认情况下,docker rm 命令只能删除处于终止或退出状态的容器,并不能删除还处于运行状态的容器。

如果要直接删除一个运行中的容器,可以添加 - f 参数。Docker 会先发送 SIGKILL 信号给容器,终止其中的应用,之后强行删除。

wohu@iZm5egn5zptnov4j3oxh4fZ:~/docker$ docker ps -a
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                      PORTS               NAMES
89860f528c9a        ubuntu:16.04        "/bin/echo 'this is …"   19 minutes ago      Exited (0) 7 minutes ago                        admiring_driscoll
acb806366cf1        ubuntu:16.04        "/bin/bash"              28 minutes ago      Up 5 minutes                                    gifted_bartik
c6813fb16675        ubuntu:16.04        "/bin/echo 'hello wo…"   45 minutes ago      Exited (0) 45 minutes ago                       determined_blackwell
1f51e44dab22        ubuntu:16.04        "/bin/bash"              About an hour ago   Exited (0) 13 minutes ago                       confident_wu
33197473a278        hello-world         "/hello"                 6 days ago          Exited (0) 6 days ago                           frosty_galileo
wohu@iZm5egn5zptnov4j3oxh4fZ:~/docker$ docker rm ac
Error response from daemon: You cannot remove a running container acb806366cf1e0374c5fd3eeac2e1d0a227fe88ae3b30006e0c6c0e2f1800348. Stop the container before attempting removal or force remove
wohu@iZm5egn5zptnov4j3oxh4fZ:~/docker$ docker rm -f ac
ac
wohu@iZm5egn5zptnov4j3oxh4fZ:~/docker$ docker ps -a
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                         PORTS               NAMES
89860f528c9a        ubuntu:16.04        "/bin/echo 'this is …"   20 minutes ago      Exited (0) 7 minutes ago                           admiring_driscoll
c6813fb16675        ubuntu:16.04        "/bin/echo 'hello wo…"   About an hour ago   Exited (0) About an hour ago                       determined_blackwell
1f51e44dab22        ubuntu:16.04        "/bin/bash"              About an hour ago   Exited (0) 14 minutes ago                          confident_wu
33197473a278        hello-world         "/hello"                 6 days ago          Exited (0) 6 days ago                              frosty_galileo
wohu@iZm5egn5zptnov4j3oxh4fZ:~/docker$ 

6. 导出容器

docker export[-o|-- output[=""]]CONTAINER

导出容器是指导出一个已经创建的容器到一个文件,不管此时这个容器是否处于运行状态,可以使用 docker export 命令,其中,可以通过 - o 选项来指定导出的 tar 文件名,也可以直接通过重定向来实现。

wohu@iZm5egn5zptnov4j3oxh4fZ:~/docker$ docker ps -a
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                         PORTS               NAMES
89860f528c9a        ubuntu:16.04        "/bin/echo 'this is …"   20 minutes ago      Exited (0) 7 minutes ago                           admiring_driscoll
c6813fb16675        ubuntu:16.04        "/bin/echo 'hello wo…"   About an hour ago   Exited (0) About an hour ago                       determined_blackwell
1f51e44dab22        ubuntu:16.04        "/bin/bash"              About an hour ago   Exited (0) 14 minutes ago                          confident_wu
33197473a278        hello-world         "/hello"                 6 days ago          Exited (0) 6 days ago                              frosty_galileo
wohu@iZm5egn5zptnov4j3oxh4fZ:~/docker$ docker export -o 111.tar 89
wohu@iZm5egn5zptnov4j3oxh4fZ:~/docker$ docker export 89 > 222.tar
wohu@iZm5egn5zptnov4j3oxh4fZ:~/docker$ ls
111.tar  222.tar  ubuntu.tar
wohu@iZm5egn5zptnov4j3oxh4fZ:~/docker$ 

之后,可将导出的 tar 文件传输到其他机器上,然后再通过导入命令导入到系统中,从而实现容器的迁移。

7. 导入容器

导出的文件又可以使用 docker import 命令导入变成镜像。

wohu@iZm5egn5zptnov4j3oxh4fZ:~/docker$ ls
111.tar  222.tar  ubuntu.tar
wohu@iZm5egn5zptnov4j3oxh4fZ:~/docker$ cat 222.tar | docker import - 222_import:v1.0
sha256:78ca641fd62347d9017eed3f1dbf5f1d5df05349b52c557f0b048ae444150421
wohu@iZm5egn5zptnov4j3oxh4fZ:~/docker$ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
222_import          v1.0                78ca641fd623        19 seconds ago      85.9MB
test_image          latest              1cd880207b3e        3 days ago          116MB
ubuntu              16.04               a51debf7e1eb        2 weeks ago         116MB
hello-world         latest              4ab4c602aa5e        3 months ago        1.84kB
wohu@iZm5egn5zptnov4j3oxh4fZ:~/docker$ 

实际上,既可以使用 docker load 命令来导入镜像存储文件到本地镜像库,也可以使用 docker import 命令来导入一个容器快照到本地镜像库。

  • docker load 适用于镜像
  • docker import 适用于容器

这两者的区别在于容器快照文件将丢弃所有的历史记录和元数据信息 (即仅保存容器当时的快照状态),而镜像存储文件将保存完整记录,体积也更大。此外,从容器快照文件导入时可以重新指定标签等元数据信息。

8. 容器的生命周期

Docker 入门系列(3)- Docker 容器(创建、启动、终止、进入、删除、导入、导出容器、容器和镜像转化)_第1张图片

9. docker kill 和 docker stop 区别

在上面关于docker容器生命周期管理中stop 和 kill 都是关闭容器,但是其中的kill是怎么实现强制杀死运行中的容器的呢?

这里需要说明下关linux下关于终止进程的信号:SIGTERM 和 SIGKILL

SIGKILL信号:无条件终止进程信号。进程接收到该信号会立即终止,不进行清理和暂存工作。该信号不能被忽略、处理和阻塞,它向系统管理员提供了可以杀死任何进程的方法。

SIGTERM信号:程序终结信号,可以由kill命令产生。与SIGKILL不同的是,SIGTERM信号可以被阻塞和终止,以便程序在退出前可以保存工作或清理临时文件等。

docker stop 会先发出SIGTERM信号给进程,告诉进程即将会被关闭。在-t指定的等待时间过了之后,将会立即发出SIGKILL信号,直接关闭容器。

docker kill 直接发出SIGKILL信号关闭容器。但也可以通过-s参数修改发出的信号。

docker restart 中同样可以设置 -t 等待时间,当等待时间过后会立刻发送SIGKILL信号,直接关闭容器。

因此会发现在docker stop的等待过程中,如果终止docker stop的执行,容器最终没有被关闭。而docker kill几乎是立刻发生,无法撤销。

10. 容器和镜像转换关系Docker 入门系列(3)- Docker 容器(创建、启动、终止、进入、删除、导入、导出容器、容器和镜像转化)_第2张图片

11. 查看容器内部细节

可用通过如下命令 docker insepct 查看容器内部细节,返回为 json

docker insepct container-id

12. 容器和宿主机互相拷贝文件

  • 宿主机拷贝文件到容器:
docker cp 文件 container-id:目标文件/文件夹

示例:

docker cp /tmp/test.txt 7f237caad43b:/tmp

将宿主机 /tmp/test.txt 文件拷贝到容器 7f237caad43b中 /tmp 目录中。

  • 从容器拷贝文件到宿主机:
docker cp container-id:目标文件/文件夹 宿主机目标文件/文件夹

示例:

docker cp 7f237caad43b:/tmp/log.log  /tmp

将容器 7f237caad43b 中 /tmp/log.log 拷贝到宿主机 /tmp 目录下。

13. 查看容器日志

查看容器实时运行的日志

docker logs -f -t --tail=行数  容器ID或容器名

查看容器从某个时刻开始的日志

docker logs -f -t --since="2018-11-28" --tail=10  容器ID或容器名

14. 容器主进程

在 Docker 的设计中,容器的生命周期其实与容器中 PID 为 1 这个进程有着密切的关系。更确切的说,它们其实是共患难,同生死的兄弟。容器的启动,本质上可以理解为这个进程的启动,而容器的停止也就意味着这个进程的停止,反过来理解亦然。

当我们启动容器时,Docker 其实会按照镜像中的定义,启动对应的程序,并将这个程序的主进程作为容器的主进程 ( 也就是 PID 为 1 的进程 )。而当我们控制容器停止时,Docker 会向主进程发送结束信号,通知程序退出。

而当容器中的主进程主动关闭时 ( 正常结束或出错停止 ),也会让容器随之停止。

通过之前提到的几个方面来看,Docker 不仅是从设计上推崇轻量化的容器,也是许多机制上是以此为原则去实现的。所以,我们最佳的 Docker 实践方法是遵循着它的逻辑,逐渐习惯这种容器即应用,应用即容器的虚拟化方式。虽然在 Docker 中我们也能够实现在同一个容器中运行多个不同类型的程序,但这么做的话,Docker 就无法跟踪不同应用的生命周期,有可能造成应用的非正常关闭,进而影响系统、数据的稳定性。

15. 写时复制机制

写时复制 ( Copy on Write ) 这个词对于开发者来说应该并不陌生,在很多编程语言里,都隐藏了写时复制的实现。在编程里,写时复制常常用于对象或数组的拷贝中,当我们拷贝对象或数组时,复制的过程并不是马上发生在内存中,而只是先让两个变量同时指向同一个内存空间,并进行一些标记,当我们要对对象或数组进行修改时,才真正进行内存的拷贝。

Docker 的写时复制与编程中的相类似,也就是在通过镜像运行容器时,并不是马上就把镜像里的所有内容拷贝到容器所运行的沙盒文件系统中,而是利用 UnionFS 将镜像以只读的方式挂载到沙盒文件系统中。只有在容器中发生对文件的修改时,修改才会体现到沙盒环境上。

也就是说,容器在创建和启动的过程中,不需要进行任何的文件系统复制操作,也不需要为容器单独开辟大量的硬盘空间,与其他虚拟化方式对这个过程的操作进行对比,Docker 启动的速度可见一斑。

采用写时复制机制来设计的 Docker,既保证了镜像在生成为容器时,以及容器在运行过程中,不会对自身造成修改。又借助剔除常见虚拟化在初始化时需要从镜像中拷贝整个文件系统的过程,大幅提高了容器的创建和启动速度。可以说,Docker 容器能够实现秒级启动速度,写时复制机制在其中发挥了举足轻重的作用。

16. attach

Docker 为我们提供了一个 docker attach 命令,用于将当前的输入输出流连接到指定的容器上。

docker attach nginx

这个命令最直观的效果可以理解为我们将容器中的主程序转为了“前台”运行 ( 与 docker run 中的 -d 选项有相反的意思 )。

由于我们的输入输出流衔接到了容器的主程序上,我们的输入输出操作也就直接针对了这个程序,而我们发送的 Linux 信号也会转移到这个程序上。例如我们可以通过 Ctrl + C 来向程序发送停止信号,让程序停止 ( 从而容器也会随之停止 )。

你可能感兴趣的:(Docker,Docker,容器,新建容器,镜像和容器转化)