首先,确保 Docker 就绪。在命令行运行 docker info ,看看 Docker 是否存在和正常。
运行第一个容器
docker run -i -t ubuntu /bin/bash
对命令产生疑问,可以使用docker help命令来查看命令说明
在第一条命令中,我们先告诉了 Docker 执行 docker run 命令,并指定了 -i -t 两个命令行参数。其中 -i 表示开启 STDIN,-t 表示 Docker 要为创建的容器分配一个伪 tty 终端。这样新创建的容器才能提供一个交互式 shell。
接下来,我们指明了使用 ubuntu 镜像来创建容器。ubuntu 镜像是一个常备镜像,可作为“基础(base)”镜像,类似的镜像还有 fedora、debian、centos,它们都是由 Docker 官方提供的,保存在 Docker Hub Registry 上。
实际上发生了什么?
- 首先,Docker 在本地查找 ubuntu 镜像(由于我们没有指明镜像的版本,默认为最新版镜像 ubuntu:latest ),如果没有找到,就连接官方 Docker Hub Registry 查看 Docker Hub 中有没有 ubuntu 镜像。一旦找到就会下载到本地宿主机中。
- 随后,Docker 在文件系统内用这个镜像创建了一个容器。容器拥有自己的网络、IP,以及一个用来和宿主机进行通信的桥接网络接口。
- 最后,我们告诉 Docker 在新容器中要执行什么命令,例中我们执行了 /bin/bash 。当容器创建完毕,Docker 就会执行容器中的 /bin/bash 命令,就可以看到容器中的 shell 了。
root@10871b426af0:/#
容器命名
docker run --name my_ubuntu -i -t ubuntu /bin/bash
上述命令将会创建名为 my_ubuntu 的容器。一个合法的容器名只能包含以下字符:a-z、A-Z、0-9、下划线、句号、减号,用正则表达式表示为 [a-zA-Z0-9-_.](因为句号在正则表达式中为通配字符,所以请把 . 理解为转义后的句号)。
在 Docker 中可以用容器名、UUID 缩写、UUID 来唯一指定一个容器。但是推荐为容器命名,这样更加方便理解与管理。
容器的命名不可重复,如果试图创建和已有容器相同名称的新容器,命令会执行失败。可以先执行 docker rm 命令删除已有容器,再创建新容器。
查看容器
docker ps 命令可以显示当前正在运行的容器;如果指定参数 -a ,则可以显示所有容器;指定参数 -l ,则只显示最后一个启动的容器。还可以使用 docker ps -n x命令,它会显示最后x个容器,不论这些容器的运行状态如何。
启动停止的容器
docker start 与 docker restart 这两个命令,前者可以启动已经停止的容器,后者无论容器处于运行还是停止状态都可以重新启动容器。
类似地,docker create 命令可以创建一个容器,但不运行它。
附着到容器上
执行 docker attach 命令,可以附着到处于运行状态容器的会话上。如果用在上面的 ubuntu 容器,则会进入 shell,此时如果退出 shell,容器也将停止。
创建守护式容器
除了上述的交互式容器(interactive container),也可以创建长期运行的容器。守护式容器(daemonized container)没有交互式会话,适合运行应用程序和服务。
在 docker run 命令中指定 -d 参数,Docker 便会创建守护式容器放到后台运行。
docker run --name daemon_hello_world -d ubuntu /bin/sh -c "while true; do echo hello world; sleep 1; done"
该命令创建了一个守护式容器,并于后台运行,运行后执行了循环打印 hello world 的命令。
看看容器内部在做什么
针对上面的例子,我们知道容器正在每隔1秒打印一条 hello world 日志。使用以下命令可以参看容器的日志:
docker logs daemon_hello_world
它将获取到最后的一些日志并返回。我们还可以对 docker logs 命令指定 -f 参数来跟踪打印日志,-t 参数用于显示日志的打印时间。可以这样指定参数 -ft。
docker logs 命令还可以指定参数 --tail 7 表示只打印最后的7条日志。 下面我们结合使用一下:
docker logs --tail 3 -ft daemon_hello_world 这条命令就表示,立刻打印最近3条日志并跟踪打印日志,且每行打印都带有时间戳。
2019-03-11T16:34:38.962240900Z hello world
2019-03-11T16:34:39.963360400Z hello world
2019-03-11T16:34:40.964409500Z hello world
2019-03-11T16:34:41.964991100Z hello world
2019-03-11T16:34:42.966022100Z hello world
2019-03-11T16:34:43.967181500Z hello world
查看容器中的进程
docker top daemon_hello_world
执行结果:
PID USER TIME COMMAND
19039 root 0:00 /bin/sh -c while true; do echo hello world; sleep 1;done
19143 root 0:00 sleep 1
Docker统计信息
docker stats
该命令可以显示一个或多个容器的统计信息。输出样式如下:
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
6174c0b2ac26 daemon_hello_world 0.14% 968KiB / 1.934GiB 0.05% 928B / 0B 2.16MB / 0B 2
4dc6ef70adf6 redis 0.14% 1.977MiB / 1.934GiB 0.10% 3.38kB / 0B 8.53MB / 0B 4
658af9c3a304 mysql 8.12% 376.4MiB / 1.934GiB 19.00% 6.52MB / 29.4MB 113MB / 22.5MB 35
ce5da739a2a3 rabbitmq 0.33% 88.3MiB / 1.934GiB 4.46% 2.88kB / 0B 39.9MB / 123kB 88
在容器内运行进程
使用 docker exec 命令在新容器内额外启动新进程。容器内运行的进程有两种:后台任务和交互式任务(须保持在前台)。
docker exec -d daemon_hello_world touch /etc/new_config_file
上面的命令中 -d 表明要运行的是一个后台进程,命令在容器中新建了 /etc/new_config_file 空文件。
我们还可以使用命令 docker exec -i -t daemon_hello_world /bin/bash ,在 daemon_hello_world 容器中创建一个新的 bash 会话。
停止守护式容器
可以使用 docker stop 停止正在运行的容器。如果想快速停止容器,还可以使用 docker kill 命令。
docker stop 向容器进程发送 SIGTERM 新号。而 docker kill 向容器发送 SIGKILL 新号。
自动重启的容器
默认的容器是不会自动重启的,通过 --restart 标志,可以让 Docker 自动重新启动容器。
docker run --restart=always --name daemon_restart -d ubuntu /bin/sh -c "while true; do echo hello xxx; sleep 1; done"
上面的命令中 --restart 标志被设置为 always 。表示无论容器的退出代码是什么,Docker 都会自动重启该容器。还可以设置为 on-failure ,如此只有当退出码不为 0 的时候,才会重启;同时 on-failure 还接受一个重启次数可选参数,--restart=on-failure:5,没错这条命令表示当异常退出容器时,最多重启5次。
删除容器
可以使用 docker rm 来删除不用的容器。默认执行是不可以删除运行中的容器的,但是可以使用 -f 标志来强制删除正在运行的容器。
如果你想一次性删除所有的容器,可以使用以下命令
docker rm `docker ps -a -q`
注意:命令中的符号 ` 不是单引号,而是Tab键上方的那个反单引号,我第一次看的时候就看错了。
上面的命令中的 -q 表示只列出容器的 ID,如果对命令参数有什么疑问,可以使用help命令查看。比如上面这个命令中,我对-q标志有疑问,可以使用 docker help ps 来查看详细的命令说明。
深入容器
除了通过 docker ps 获取获取容器信息,还可以用 docker inspect 来获得更多的容器信息。
执行:docker inspect daemon_hello_world
结果:
[
{
"Id": "64ded64e3207d3583a19e1ac4d8ed86f6813e2d06764c7b618b3bb52911ac8ef",
"Created": "2019-03-12T11:01:33.8559955Z",
"Path": "/bin/sh",
"Args": [
"-c",
"while true; do echo hello world; sleep 1; done"
],
"State": {
"Status": "running",
"Running": true,
"Paused": false,
"Restarting": false,
"OOMKilled": false,
"Dead": false,
"Pid": 6588,
"ExitCode": 0,
"Error": "",
"StartedAt": "2019-03-12T11:01:34.5640346Z",
"FinishedAt": "0001-01-01T00:00:00Z"
},
"Image": "sha256:47b19964fb500f3158ae57f20d16d8784cc4af37c52c49d3b4f5bc5eede49541",
"ResolvConfPath": "/var/lib/docker/containers/64ded64e3207d3583a19e1ac4d8ed86f6813e2d06764c7b618b3bb52911ac8ef/resolv.conf",
"HostnamePath": "/var/lib/docker/containers/64ded64e3207d3583a19e1ac4d8ed86f6813e2d06764c7b618b3bb52911ac8ef/hostname",
"HostsPath": "/var/lib/docker/containers/64ded64e3207d3583a19e1ac4d8ed86f6813e2d06764c7b618b3bb52911ac8ef/hosts",
"LogPath": "/var/lib/docker/containers/64ded64e3207d3583a19e1ac4d8ed86f6813e2d06764c7b618b3bb52911ac8ef/64ded64e3207d3583a19e1ac4d8ed86f6813e2d06764c7b618b3bb52911ac8ef-json.log",
"Name": "/daemon_hello_world",
"RestartCount": 0,
"Driver": "overlay2",
"Platform": "linux",
"MountLabel": "",
"ProcessLabel": "",
"AppArmorProfile": "",
"ExecIDs": null,
"HostConfig": {
"Binds": null,
"ContainerIDFile": "",
"LogConfig": {
"Type": "json-file",
"Config": {}
},
"NetworkMode": "default",
"PortBindings": {},
"RestartPolicy": {
"Name": "always",
"MaximumRetryCount": 0
},
"AutoRemove": false,
"VolumeDriver": "",
"VolumesFrom": null,
"CapAdd": null,
"CapDrop": null,
"Dns": [],
"DnsOptions": [],
"DnsSearch": [],
"ExtraHosts": null,
"GroupAdd": null,
"IpcMode": "shareable",
"Cgroup": "",
"Links": null,
"OomScoreAdj": 0,
"PidMode": "",
"Privileged": false,
"PublishAllPorts": false,
"ReadonlyRootfs": false,
"SecurityOpt": null,
"UTSMode": "",
"UsernsMode": "",
"ShmSize": 67108864,
"Runtime": "runc",
"ConsoleSize": [
50,
120
],
"Isolation": "",
"CpuShares": 0,
"Memory": 0,
"NanoCpus": 0,
"CgroupParent": "",
"BlkioWeight": 0,
"BlkioWeightDevice": [],
"BlkioDeviceReadBps": null,
"BlkioDeviceWriteBps": null,
"BlkioDeviceReadIOps": null,
"BlkioDeviceWriteIOps": null,
"CpuPeriod": 0,
"CpuQuota": 0,
"CpuRealtimePeriod": 0,
"CpuRealtimeRuntime": 0,
"CpusetCpus": "",
"CpusetMems": "",
"Devices": [],
"DeviceCgroupRules": null,
"DiskQuota": 0,
"KernelMemory": 0,
"MemoryReservation": 0,
"MemorySwap": 0,
"MemorySwappiness": null,
"OomKillDisable": false,
"PidsLimit": 0,
"Ulimits": null,
"CpuCount": 0,
"CpuPercent": 0,
"IOMaximumIOps": 0,
"IOMaximumBandwidth": 0,
"MaskedPaths": [
"/proc/asound",
"/proc/acpi",
"/proc/kcore",
"/proc/keys",
"/proc/latency_stats",
"/proc/timer_list",
"/proc/timer_stats",
"/proc/sched_debug",
"/proc/scsi",
"/sys/firmware"
],
"ReadonlyPaths": [
"/proc/bus",
"/proc/fs",
"/proc/irq",
"/proc/sys",
"/proc/sysrq-trigger"
]
},
"GraphDriver": {
"Data": {
"LowerDir": "/var/lib/docker/overlay2/f84227ba5382db67d06e819a3a4c16230bb2dfa3f2daab5054c0935d79fd5c2a-init/diff:/var/lib/docker/overlay2/8a9e1bb011fe79aa7d9a139a55f4bc00fa9ede6e9ba877b23f20110b9dceb600/diff:/var/lib/docker/overlay2/430a6679897b4216a7b5cb76a32197aba98c6d539b08ee23bb23f0e9a3a070c6/diff:/var/lib/docker/overlay2/99d8f0e93a56d6b8147d50b09dd937a0fcc2d34a2a76f71b782cc7b27891d4ca/diff:/var/lib/docker/overlay2/585e92baad5fb64f4b3aa63992f39c8746be7f8c5429bef61257a9595738aa83/diff",
"MergedDir": "/var/lib/docker/overlay2/f84227ba5382db67d06e819a3a4c16230bb2dfa3f2daab5054c0935d79fd5c2a/merged",
"UpperDir": "/var/lib/docker/overlay2/f84227ba5382db67d06e819a3a4c16230bb2dfa3f2daab5054c0935d79fd5c2a/diff",
"WorkDir": "/var/lib/docker/overlay2/f84227ba5382db67d06e819a3a4c16230bb2dfa3f2daab5054c0935d79fd5c2a/work"
},
"Name": "overlay2"
},
"Mounts": [],
"Config": {
"Hostname": "64ded64e3207",
"Domainname": "",
"User": "",
"AttachStdin": false,
"AttachStdout": false,
"AttachStderr": false,
"Tty": false,
"OpenStdin": false,
"StdinOnce": false,
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
],
"Cmd": [
"/bin/sh",
"-c",
"while true; do echo hello world; sleep 1; done"
],
"Image": "ubuntu",
"Volumes": null,
"WorkingDir": "",
"Entrypoint": null,
"OnBuild": null,
"Labels": {}
},
"NetworkSettings": {
"Bridge": "",
"SandboxID": "2cc78ade49335bcd8ea4e319b9a8623aae807e75d24dc8b62112b557710a9964",
"HairpinMode": false,
"LinkLocalIPv6Address": "",
"LinkLocalIPv6PrefixLen": 0,
"Ports": {},
"SandboxKey": "/var/run/docker/netns/2cc78ade4933",
"SecondaryIPAddresses": null,
"SecondaryIPv6Addresses": null,
"EndpointID": "d8e464ae9ea5f91625c24ca59898edb990cc9046f131345ec9ba39cfb0a870e0",
"Gateway": "172.17.0.1",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"IPAddress": "172.17.0.5",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"MacAddress": "02:42:ac:11:00:05",
"Networks": {
"bridge": {
"IPAMConfig": null,
"Links": null,
"Aliases": null,
"NetworkID": "fb546420908ebd183567666f618142803234d185b401fbe1b7dd3500553c3a35",
"EndpointID": "d8e464ae9ea5f91625c24ca59898edb990cc9046f131345ec9ba39cfb0a870e0",
"Gateway": "172.17.0.1",
"IPAddress": "172.17.0.5",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"MacAddress": "02:42:ac:11:00:05",
"DriverOpts": null
}
}
}
}
]
docker inspect 还可以用 -f --format 标志选定查看结果,以及也可以同时指定多个容器。
执行:docker inspect -f '{{.NetworkSettings.IPAddress}}' daemon_hello_world redis mysql
结果:
172.17.0.5
172.17.0.2
172.17.0.3
至此,你学会了一些基本的 docker 命令,但是还没到能实用的地步,让我们继续下一篇吧。