上节学习了镜像(image),本节学习容器(container)。
一、基本概念
容器是 Docker 的三个基本概念中的又一核心概念。容器是镜像的运行时实例。可以从单个镜像上启动一个或多个容器。简单的说,容器是独立运行的一个或一组应用,以及它们的运行态环境。对应的,虚拟机可以理解为模拟运行的一整套操作系统(提供了运行态环境和其他系统环境)和跑在上面的应用。
再来温习一下虚拟机和容器的差异:
虚拟机和容器最大的区别是容器更快并且更轻量级——与虚拟机运行在完整的操作系统之上相比,容器会共享其所在主机的操作系统/内核。
二、基本操作
1、启动容器
基于一个镜像启动容器的命令:
docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
下面以操作镜像 centos 为例,来启动一个centos 应用的容器。
docker run -it centos
参数说明:
- -i: 交互式操作,让容器的标准输入保持打开。
- -t: 终端,Docker分配一个伪终端(pseudo-tty)并绑定到容器的标准输入上。
- centos: centos 镜像。
在交互模式下,用户可以通过所创建的终端来输入命令。
仔细观察,就会发现 Shell 提示符发生了变化,说明目前已经位于容器内部了。在上面的示例中,Shell 提示符已经变为 root@12e7a7b65fea:/#。@ 之后的一长串数字就是容器唯一 ID 的前 12 个字符。若尝试在容器内执行一些基础命令,可能会发现某些指令无法正常工作。这是因为大部分容器镜像都是经过高度优化的。这意味着某些命令或者包可能没有安装。
当利用 docker run
来创建容器时,Docker 在后台运行的标准操作包括:
- 检查本地是否存在指定的镜像,不存在就从公有仓库下载
- 利用镜像创建并启动一个容器
- 分配一个文件系统,并在只读的镜像层外面挂载一层可读写层
- 从宿主主机配置的网桥接口中桥接一个虚拟接口到容器中去
- 从地址池配置一个 ip 地址给容器
- 执行用户指定的应用程序
- 执行完毕后容器被终止
要退出终端,直接输入 exit:
exit
启动已终止容器
可以利用 docker start
容器的核心为所执行的应用程序,所需要的资源都是应用程序运行所必需的。除此之外,并没有其它的资源。可以在伪终端中利用 ps
或 top
来查看进程信息。
可见,容器中仅运行了指定的 bash 应用。这种特点使得 Docker 对资源的利用率极高,是货真价实的轻量级虚拟化。
2、守护态运行
更多的时候,需要让 Docker 在后台运行而不是直接把执行命令的结果输出在当前宿主机下。此时,可以通过添加 -d
参数来实现。
下面举两个例子来说明一下。
如果不使用 -d
参数运行容器。
docker run centos:latest /bin/sh -c "while true; do echo hello world; sleep 1; done"
容器会把输出的结果 (STDOUT) 打印到宿主机上面
如果使用了 -d
参数运行容器。
docker run centos:latest /bin/sh -c "while true; do echo hello world; sleep 1; done"
此时容器会在后台运行并不会把输出的结果 (STDOUT) 打印到宿主机上面。
输出结果可以用 docker logs
查看:
docker logs [OPTIONS] CONTAINER
参数说明:
CONTAINER:容器ID 或容器name
注: 容器是否会长久运行,是和 docker run
指定的命令有关,和 -d
参数无关。
使用 -d
参数启动后会返回一个唯一的 id,也可以通过 docker container ls
或 docker ps 命令来查看容器信息。
要获取容器的输出信息,可以通过 docker container logs
命令。
注:加了 -d 参数默认不会进入容器,想要进入容器需要使用指令 docker exec(下面会介绍到)。
3、终止容器
可以使用 docker stop
来终止一个运行中的容器。
docker stop <容器 ID>
此外,当 Docker 容器中指定的应用终结时,容器也自动终止。
例如对于上一章节中只启动了一个终端的容器,用户通过 exit
命令或 Ctrl+d
来退出终端时,所创建的容器立刻终止。
终止状态的容器可以用 docker ps -a
命令看到。例如
处于终止状态的容器,可以通过 docker start
docker restart <容器 ID>
此外,docker restart
命令会将一个运行态的容器终止,然后再重新启动它。
docker restart <容器 ID>
4、进入容器
在使用 -d 参数时,容器启动后会进入后台,以守护态运行。此时想要进入容器,可以通过以下指令进入:
- docker attach [容器ID]
- docker exec [容器ID]
推荐大家使用 docker exec 命令,因为此退出容器终端,不会导致容器的停止。
attach 命令
下面演示了使用 docker attach 命令。
注:如果从这个容器退出,会导致容器的停止。
exec 命令
下面演示了使用 docker exec 命令。
可以看到我使用进入命令进入容器,报错提示这个容器未运行,验证了之前的说法,我重启后再次进入即可
注意
:如果从这个容器退出,不会导致容器的停止,这就是为什么推荐大家使用 docker exec 的原因。
docker exec
后边可以跟多个参数,这里主要说明 -i
-t
参数。
只用 -i
参数时,由于没有分配伪终端,界面没有我们熟悉的 Linux 命令提示符,但命令执行结果仍然可以返回。
当 -i
-t
参数一起使用时,则可以看到我们熟悉的 Linux 命令提示符。
更多参数说明请使用 docker exec --help
命令查看。
5、导出容器
如果要导出本地某个容器,可以使用 docker export
这样将导出容器快照到本地文件。
6、导入容器
可以使用 docker import
从容器快照文件中再导入为镜像,
Usage: docker import [OPTIONS] file|URL|- [REPOSITORY[:TAG]]
例如:
此外,也可以通过指定 URL 或者某个目录来导入,例如
[root@iZ8vbdmp7p7nu6o38oalgoZ ~]# docker import http://example.com/exampleimage.tgz example/imagerepo
注:用户既可以使用 docker load
来导入镜像存储文件到本地镜像库,也可以使用 docker import
7、删除容器
可以使用 docker rm
Usage: docker rm [OPTIONS] CONTAINER [CONTAINER...]
例如:
[root@Roker~]# docker rm myDemo
myDemo
[root@Roker~]#
如果要删除一个运行中的容器,可以添加 -f
参数。Docker 会发送 SIGKILL
信号给容器。
清理所有处于终止状态的容器
用 docker ps -a
docker container prune
8、查看容器详情
显示容器的配置细节和运行时信息。该命令接收容器名称和容器 ID 作为主要参数。
Usage: docker inspect [OPTIONS] NAME|ID [NAME|ID...]
[root@iZ8vbdmp7p7nu6o38oalgoZ ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
eb31302470a4 mysql "docker-entrypoint..." 4 days ago Up 19 hours 0.0.0.0:3306->3306/tcp, 33060/tcp mysql
[root@iZ8vbdmp7p7nu6o38oalgoZ ~]# docker inspect eb31302470a4
[
{
"Id": "eb31302470a446421a4c53712437e10e3d17e4d052181154cb1871c9e0b7e30c",
"Created": "2020-07-03T09:14:07.298906124Z",
"Path": "docker-entrypoint.sh",
"Args": [
"mysqld"
],
"State": {
"Status": "running",
"Running": true,
"Paused": false,
"Restarting": false,
"OOMKilled": false,
"Dead": false,
"Pid": 16484,
"ExitCode": 0,
"Error": "",
"StartedAt": "2020-07-07T07:11:09.879088408Z",
"FinishedAt": "2020-07-07T05:35:31.816272022Z"
},
"Image": "sha256:be0dbf01a0f3f46fc8c88b67696e74e7005c3e16d9071032fa0cd89773771576",
"ResolvConfPath": "/var/lib/docker/containers/eb31302470a446421a4c53712437e10e3d17e4d052181154cb1871c9e0b7e30c/resolv.conf",
"HostnamePath": "/var/lib/docker/containers/eb31302470a446421a4c53712437e10e3d17e4d052181154cb1871c9e0b7e30c/hostname",
"HostsPath": "/var/lib/docker/containers/eb31302470a446421a4c53712437e10e3d17e4d052181154cb1871c9e0b7e30c/hosts",
"LogPath": "",
"Name": "/mysql",
"RestartCount": 0,
"Driver": "overlay2",
"MountLabel": "",
"ProcessLabel": "",
"AppArmorProfile": "",
"ExecIDs": null,
"HostConfig": {
"Binds": null,
"ContainerIDFile": "",
"LogConfig": {
"Type": "journald",
"Config": {}
},
"NetworkMode": "default",
"PortBindings": {
"3306/tcp": [
{
"HostIp": "",
"HostPort": "3306"
}
]
},
"RestartPolicy": {
"Name": "no",
"MaximumRetryCount": 0
},
"AutoRemove": false,
"VolumeDriver": "",
"VolumesFrom": null,
"CapAdd": null,
"CapDrop": null,
"Dns": [],
"DnsOptions": [],
"DnsSearch": [],
"ExtraHosts": null,
"GroupAdd": null,
"IpcMode": "",
"Cgroup": "",
"Links": null,
"OomScoreAdj": 0,
"PidMode": "",
"Privileged": false,
"PublishAllPorts": false,
"ReadonlyRootfs": false,
"SecurityOpt": null,
"UTSMode": "",
"UsernsMode": "",
"ShmSize": 67108864,
"Runtime": "docker-runc",
"ConsoleSize": [
0,
0
],
"Isolation": "",
"CpuShares": 0,
"Memory": 0,
"NanoCpus": 0,
"CgroupParent": "",
"BlkioWeight": 0,
"BlkioWeightDevice": null,
"BlkioDeviceReadBps": null,
"BlkioDeviceWriteBps": null,
"BlkioDeviceReadIOps": null,
"BlkioDeviceWriteIOps": null,
"CpuPeriod": 0,
"CpuQuota": 0,
"CpuRealtimePeriod": 0,
"CpuRealtimeRuntime": 0,
"CpusetCpus": "",
"CpusetMems": "",
"Devices": [],
"DiskQuota": 0,
"KernelMemory": 0,
"MemoryReservation": 0,
"MemorySwap": 0,
"MemorySwappiness": -1,
"OomKillDisable": false,
"PidsLimit": 0,
"Ulimits": null,
"CpuCount": 0,
"CpuPercent": 0,
"IOMaximumIOps": 0,
"IOMaximumBandwidth": 0
},
"GraphDriver": {
"Name": "overlay2",
"Data": {
"LowerDir": "/var/lib/docker/overlay2/e55c3a894a955decf9855ff9c4891e473ae91ebe0930cbe470a90d9f2b4e9d92-init/diff:/var/lib/docker/overlay2/7bd107ffabb5689f779b705daf5ffcf2c668170085d5b6e52ad834f4cb724e8d/diff:/var/lib/docker/overlay2/6bf0d8d767582ce705ba8161ffbf623aba39371b14ed8c32af30cc6b4200bc17/diff:/var/lib/docker/overlay2/307e7e6341373d2838878a29b85aa5ed7a16460be548d8a1cc33829660e217e2/diff:/var/lib/docker/overlay2/5168738ad442c95cb430279cbf9fe21b13be93b26356727cf6403a4d3039ba43/diff:/var/lib/docker/overlay2/c5b216ad92d6f71d124b4c6771d4266ffefc271b9ec9677d251c2c12bbb1408e/diff:/var/lib/docker/overlay2/0f4f3bbb8487b0a95cf15050e8eebd26e8e7498c33511a47f6fe4d2937fe1379/diff:/var/lib/docker/overlay2/5de030164b5a5f9c56de563259135e7af84ea4ce4b2829c5a0206ed8baf82c4d/diff:/var/lib/docker/overlay2/e62c1b354dfb87c17f10b40bfe1d15d5e0b0dc48e17bd3ef0a6cdd31ee3dcd1c/diff:/var/lib/docker/overlay2/3b2b9f340fec2219b9cbb792b0ec17798a0882e17abb1a63e5fe22ad1e5104d8/diff:/var/lib/docker/overlay2/561d54b951cec23637e970adc36fbef56446d898c82fdc0041aa1fc656933532/diff:/var/lib/docker/overlay2/56441d46f7c1bbd67ba7440bfd089afe3b26c778ffee983a6ac3da5e2e7fb18f/diff:/var/lib/docker/overlay2/1c25bd256e180fbeca31389e7278a26102a8f4e002c5798725a8b3af06bfb4fb/diff",
"MergedDir": "/var/lib/docker/overlay2/e55c3a894a955decf9855ff9c4891e473ae91ebe0930cbe470a90d9f2b4e9d92/merged",
"UpperDir": "/var/lib/docker/overlay2/e55c3a894a955decf9855ff9c4891e473ae91ebe0930cbe470a90d9f2b4e9d92/diff",
"WorkDir": "/var/lib/docker/overlay2/e55c3a894a955decf9855ff9c4891e473ae91ebe0930cbe470a90d9f2b4e9d92/work"
}
},
"Mounts": [
{
"Type": "volume",
"Name": "da1b1b391fb4bd7aa58273f9548c5d13d0b934e84d6d0f73d490425456b38737",
"Source": "/var/lib/docker/volumes/da1b1b391fb4bd7aa58273f9548c5d13d0b934e84d6d0f73d490425456b38737/_data",
"Destination": "/var/lib/mysql",
"Driver": "local",
"Mode": "",
"RW": true,
"Propagation": ""
}
],
"Config": {
"Hostname": "eb31302470a4",
"Domainname": "",
"User": "",
"AttachStdin": false,
"AttachStdout": false,
"AttachStderr": false,
"ExposedPorts": {
"3306/tcp": {},
"33060/tcp": {}
},
"Tty": false,
"OpenStdin": false,
"StdinOnce": false,
"Env": [
"MYSQL_ROOT_PASSWORD=000000",
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
"GOSU_VERSION=1.12",
"MYSQL_MAJOR=8.0",
"MYSQL_VERSION=8.0.20-1debian10"
],
"Cmd": [
"mysqld"
],
"ArgsEscaped": true,
"Image": "mysql",
"Volumes": {
"/var/lib/mysql": {}
},
"WorkingDir": "",
"Entrypoint": [
"docker-entrypoint.sh"
],
"OnBuild": null,
"Labels": {}
},
"NetworkSettings": {
"Bridge": "",
"SandboxID": "64f77b452c68c6e77564ddae9e1259cd5407d3e88e02eaca0992703d13da45b5",
"HairpinMode": false,
"LinkLocalIPv6Address": "",
"LinkLocalIPv6PrefixLen": 0,
"Ports": {
"3306/tcp": [
{
"HostIp": "0.0.0.0",
"HostPort": "3306"
}
],
"33060/tcp": null
},
"SandboxKey": "/var/run/docker/netns/64f77b452c68",
"SecondaryIPAddresses": null,
"SecondaryIPv6Addresses": null,
"EndpointID": "79f7bc65f7db15a7d1b5639771d0e3ad212755df49ac58ea67ae8aed6151265e",
"Gateway": "172.17.0.1",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"IPAddress": "172.17.0.2",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"MacAddress": "02:42:ac:11:00:02",
"Networks": {
"bridge": {
"IPAMConfig": null,
"Links": null,
"Aliases": null,
"NetworkID": "2c8318a19c78a634950d6a1b364604cdcf91f817ab76d3de3125159de17b527f",
"EndpointID": "79f7bc65f7db15a7d1b5639771d0e3ad212755df49ac58ea67ae8aed6151265e",
"Gateway": "172.17.0.1",
"IPAddress": "172.17.0.2",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"MacAddress": "02:42:ac:11:00:02"
}
}
}
}
]