在学习了 docker 镜像的内容后,我们在来看 docker 的另一个核心点:容器。

注:环境为 CentOS7,docker 19.03

docker 的容器是镜像的一个运行实例。docker 镜像是只读文件,而容器则带有运行时的可读写层,而且容器中的应用进程处于运行状态。接下来我们就来学习 docker 容器的具体操作。

创建容器

创建容器相关的命令有 create、start、run、wait 和 logs。

新建容器

使用命令 docker [container] create 新建一个容器:

# docker create -it ubuntu:latest
63197c11dc16e893dc8bb032ebf92419032cc40d6dcb6f750a16e9e308d52584
# docker ps -a
CONTAINER ID        IMAGE                 COMMAND                  CREATED             STATUS                  PORTS                    NAMES
63197c11dc16        ubuntu:latest         "/bin/bash"              5 seconds ago       Created                                          hardcore_raman

docker create 命令对应的参数有很多,下面列出对应的选项:

create 命令与容器运行模式相关的选项

ctf docker创建容器 docker怎么创建容器_网络


ctf docker创建容器 docker怎么创建容器_json_02


create 命令与容器环境和配置相关的选项

ctf docker创建容器 docker怎么创建容器_网络_03


create 命令与容器资源限制和安全保护相关的选项

ctf docker创建容器 docker怎么创建容器_网络_04


ctf docker创建容器 docker怎么创建容器_ctf docker创建容器_05


ctf docker创建容器 docker怎么创建容器_网络_06


ctf docker创建容器 docker怎么创建容器_json_07

以及:

  • -l, --label=[]: 以键值对⽅式指定容器的标签信息;
  • --label-file=[]: 从⽂件中读取标签信息。

启动容器

使用该命令新建的容器处于停止状态,使用命令 docker [container] start启动容器,通过 docker [container] ps查看运行中的容器:

# docker start 63197c11dc16e893dc8bb032ebf92419032cc40d6dcb6f750a16e9e308d52584
63197c11dc16e893dc8bb032ebf92419032cc40d6dcb6f750a16e9e308d52584
# docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED              STATUS              PORTS                    NAMES
63197c11dc16        ubuntu:latest       "/bin/bash"              About a minute ago   Up 3 seconds                                 hardcore_raman

我们还可以将新建和启动容器合起来,命令 docker [container] run 就是两个命令的组合:

# docker run ubuntu /bin/echo "Hello World"
Hello World
# docker ps -a
CONTAINER ID        IMAGE                 COMMAND                  CREATED             STATUS                     PORTS                    NAMES
5982bad8cf83        ubuntu                "/bin/echo 'Hello Wo…"   7 seconds ago       Exited (0) 6 seconds ago                            exciting_lalande

使用 run 命令实际上在后台包含了以下过程:

  • 检查本地是否存在指定的镜像, 不存在就从公有仓库下载;
  • 利⽤镜像创建⼀个容器, 并启动该容器;
  • 分配⼀个⽂件系统给容器, 并在只读的镜像层外⾯挂载⼀层可读写层;
  • 从宿主主机配置的⽹桥接⼜中桥接⼀个虚拟接⼜到容器中去;
  • 从⽹桥的地址池配置⼀个IP地址给容器;
  • 执⾏⽤户指定的应⽤程序;
  • 执⾏完毕后容器被⾃动终⽌。

注:运行结束后容器就会停止。

还可以在创建时启动一个 bash 终端,这样就能和容器交互了:

# docker run -it ubuntu bash
root@264cf6ed894e:/#
  • -t:选项让Docker分配⼀个伪终端(pseudo-tty) 并绑定到容器的标准输⼊上,
  • -i:则让容器的标准输⼊保持打开。

退出容器

⽤户可以按 Ctrl+d 或输⼊ exit 命令来退出容器,也可以使用命令 docker container wait CONTAINER[CONTAINER...] ⼦命令来等待容器退出, 并打印退出返回结果。

root@264cf6ed894e:/# exit
exit

如果启动容器的出项错误,有以下错误代码:

  • 125: Docker daemon执⾏出错, 例如指定了不⽀持的Docker命令参数;
  • 126: 所指定命令⽆法执⾏, 例如权限出错;
  • 127: 容器内命令⽆法找到。

后台运行

如果需要让容器在后台以守护态(Daemonized) 形式运⾏,可以通过 -d 参数实现:

# docker run -itd ubuntu /bin/bash -c "while true; do echo hello world; sleep 1; done"
5352f3e531b2f451ec6b484a6d35d1fd064438fa3d3404691b80b98bbc6e7801

它会返回一个唯一的id值,使用 docker psdocker container ls 来查看容器信息:

# docker container ls 
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                    NAMES
5352f3e531b2        ubuntu              "/bin/bash -c 'while…"   2 minutes ago       Up 2 minutes                                 lucid_albattani

查看容器输出

刚才通过 -d 让容器以后台方式运行,我们没有看到它的输出信息,可以使用命令docker [container] logs命令查看,该命令包含以下选项:

  • -details: 打印详细信息;
  • -f, -follow: 持续保持输出;
  • -since string: 输出从某个时间开始的⽇志;
  • -tail string: 输出最近的若⼲⽇志;
  • -t, -timestamps: 显⽰时间戳信息;·-until string: 输出某个时间之前的⽇志。
# docker logs 5352f3e531b2
hello world

注:创建容器后会返回一个唯一的id,但一般我们截取字符前面的一部分,保证能认到这个容器就可以了。

停止容器

停止容器使用的子命令为 pause/unpause、stop、prune。

暂停容器

使用命令docker [container] pause CONTAINER[CONTAINER...]来暂停一个运行中的容器

# docker run --name test --rm -itd ubuntu bash
c1a52ffc5f662b2e60bcd98fe81157754cb251b22a624e8a6a32785905d5b93e
# docker pause c1a52ffc5
c1a52ffc5
# docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                   PORTS                    NAMES
c1a52ffc5f66        ubuntu              "bash"                   16 seconds ago      Up 16 seconds (Paused)                            test

出于 paused 状态的容器就可以使用 docker [container] unpause CONTAINER[CONTAINER...] 命令来恢复了。

注:启动时添加 --rm 选项时,在容器退出后会删除容器。

停止容器

使用命令docker [container] stop [-t|--time[=10]] [CONTAINER...]停止容器:

# docker stop 5352f3e531b2
5352f3e531b2

现在使用命令 docker container prune 会删除所有处于停止状态的容器。

除了 stop 外,使用命令docker [container] kill或在交互模式下通过命令exitCtrl+d都可以停止容器。

属于停止状态的容器,可以使用命令 docker [container] start 来启动,或者是命令 docker [container] restart 来先停止再启动。

进入容器

当容器再后台运行是,使用 docker [container] exec 命令可以进入容器中,支持的参数有:

  • -d, --detach: 在容器中后台执⾏命令;
  • --detach-keys="": 指定将容器切回后台的按键;
  • -e, --env=[]: 指定环境变量列表;
  • -i, --interactive=true|false: 打开标准输⼊接受⽤户输⼊命令, 默认值为false;
  • --privileged=true|false: 是否给执⾏命令以⾼权限, 默认值为false;
  • -t, --tty=true|false: 分配伪终端, 默认值为false;
  • -u, --user="": 执⾏命令的⽤户名或ID。
# docker exec -it 5352f3e531b2 /bin/bash

删除容器

删除容器则是使用命令 docker [container] rm,命令的格式为 docker [container] rm [-f|--force] [-l|--link] [-v|--volumes] CONTAINER [CONTAINER...],支持以下选项:

  • -f, --force=false: 是否强⾏终⽌并删除⼀个运⾏中的容器;
  • -l, --link=false: 删除容器的连接, 但保留容器;
  • -v, --volumes=false: 删除容器挂载的数据卷
# docker rm -f 5352f3e531b2
5352f3e531b2

使用 docker rm 命令只能删除处于停止状态或退出状态的容器,并不能删除还在运行状态中的容器。但是使用选项 -f 可以删除,Docker会先发送SIGKILL信号给容器, 终⽌其中的应⽤, 之后强⾏删除。

导入和导出容器

有时我们需要将运行中的容器在不同的机器上拷贝,docker 则实现了容器的导入和导出功能。

导出容器

导出使用命令为 docker [container] export,命令格式为 docker [container] export [-o|--output[=""]] CONTAINER

# docker export -o ubuntu.tar 6f71e82ba8b1
[root@CentOS1 ~]# ls
anaconda-ks.cfg  dockerfile  ubuntu.tar

导出后的容器就可以直接复制到其他机器上导入运行了。

导入容器

使用命令 docker [container] import 则可以导入容器,格式为 docker import [-c|--change[=[]]] [-m|--message[=MESSAGE]] file|URL|-[REPOSITORY[:TAG]]

# docker import ubuntu.tar test/ubuntu:v1.0  
sha256:6ccd40df1a76c15233708df3446fb97621f05826b2f0e4780aac29f5afaf76a7
# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
test/ubuntu         v1.0                6ccd40df1a76        7 seconds ago       69.9MB

注:可以使⽤docker load命令来导⼊镜像存储⽂件到本地镜像库, 也可以使⽤docker[container]import命令来导⼊⼀个容器快照到本地镜像库。 这两者的区别在于: 容器快照⽂件将丢弃所有的历史记录和元数据信息(即仅保存容器当时的快照状态) , ⽽镜像存储⽂件将保存完整记录, 体积更⼤。 此外, 从容器快照⽂件导⼊时可以重新指定标签等元数据信息。

查看容器

查看容器有 inspect、top 和 stats 子命令。

inspect

使用命令 docker container inspect [OPTIONS] CONTAINER [CONTAINER...] 查看容器详情:

# docker inspect 6f71e82ba8b129e54dd315d79ef4
[
    {
        "Id": "6f71e82ba8b129e54dd315d79ef4ec49fc3b26cd60102adcebe8b8a39c05dd3f",
        "Created": "2019-08-21T13:22:23.432469852Z",
        "Path": "/bin/bash"
        ...
    }
]

该命令会以json格式返回包括容器Id、 创建时间、 路径、 状态、 镜像、 配置等在内的各项信息。

top

使用命令 docker [container] top [OPTIONS] CONTAINER [CONTAINER...] 查看容器内进程:

# docker container top 6f71e82b
UID                 PID                 PPID                C                   STIME               TTY                 TIME                CMD
root                16395               16376               0                   08:12               pts/0               00:00:00            /bin/bash

这个⼦命令类似于Linux系统中的top命令, 会打印出容器内的进程信息, 包括PID、 ⽤户、 时间、 命令等。

stats

使用命令 docke r[container] stats [OPTIONS] [CONTAINER...] 查看容器统计信息:
⽀持选项包括:

  • -a, -all: 输出所有容器统计信息, 默认仅在运⾏中;
  • --format string: 格式化输出信息;
  • --no-stream: 不持续输出, 默认会⾃动更新持续实时结果;
  • --no-trunc: 不截断输出信息。

其他命令

除此之外,docker 容器还支持其他类型的命令,如 cp、diff、port 和 update 子命令。

cp

该命令支持在容器和主机之间复制文件。命令格式为 docker [container] cp [OPTIONS] CONTAINER: SRC_PATH DEST_PATH|-,支持的选项:

  • -a, -archive: 打包模式, 复制⽂件会带有原始的uid/gid信息;
  • -L, -follow-link: 跟随软连接。 当原路径为软连接时, 默认只复制链接信息, 使⽤该选项会复制链接的⽬标内容。
# docker container cp /etc/passwd 6f71e82ba8b1:/tmp/

diff

diff 查看容器内文件系统的变更,格式为 docker[container]diff CONTAINER

# docker container diff 6f71e82ba8b1
C /tmp
A /tmp/passwd

因为上面将文件复制到容器中,所以看到容器的文件系统发生了变化,C 为 改变,A 为追加

port

port 用来查看容器的端口映射情况,命令格式为 docker container port CONTAINER [PRIVATE_PORT [/PROTO]]

# docker container port 07a4e1582bd1
3306/tcp -> 0.0.0.0:3306

update

update 可以更新容器运行时配置,命令格式为 docker [container] update [OPTIONS] CONTAINER [CONTAINER...],支持选项有:

  • --blkio-weight uint16: 更新块IO限制, 10~1000, 默认值为0, 代表着⽆限制;
  • --cpu-period int: 限制CPU调度器CFS(Completely Fair Scheduler) 使⽤时间, 单位为微秒, 最⼩1000;
  • --cpu-quota int: 限制CPU调度器CFS配额, 单位为微秒, 最⼩1000;
  • --cpu-rt-period int: 限制CPU调度器的实时周期, 单位为微秒;
  • --cpu-rt-runtime int: 限制CPU调度器的实时运⾏时, 单位为微秒;
  • -c, -cpu-shares int: 限制CPU使⽤份额;
  • --cpus decimal: 限制CPU个数;
  • --cpuset-cpus string: 允许使⽤的CPU核, 如0-3, 0, 1;
  • --cpuset-mems string: 允许使⽤的内存块, 如0-3, 0, 1;
  • --kernel-memory bytes: 限制使⽤的内核内存;
  • -m, -memory bytes: 限制使⽤的内存;
  • --memory-reservation bytes: 内存软限制;
  • --memory-swap bytes: 内存加上缓存区的限制, -1表⽰为对缓冲区⽆限制;
  • --restart string: 容器退出后的重启策略

比如限制 docker 容器的内存和cpu:

# docker container update -m 1g --memory-swap 1g --cpus 1 6f71e82ba8b1   
6f71e82ba8b1