文章

Docker实验二:Docker容器

1 实验内容

  • 学习Docker容器的常用命令。

2 实验要点

  • 掌握Docker容器的常用命令。

3 实验环境

  • Windows 7 Docker环境

4 注意事项

Docker官方对docker pull指令进行了限制,同一个IP每6小时最多使用100次,如果pull上限后,可以尝试下载相应的images,然后使用docker load命令直接加载相应的镜像。

例如:

1
docker load < images/ubuntu_latest.tar.gz

5 实验步骤

5.1 Docker 客户端

docker 客户端非常简单 ,可以直接输入 docker 命令或docker --help来查看到 Docker 客户端的所有命令选项。 image-20210916163711500

可通过命令docker command --help深入了解某个Docker命令使用方法。

例如要查看docker run的具体使用方法: image-20210916164154451

5.2 容器的使用

5.2.1 获取镜像

如果本地没有ubuntu镜像,可使用docker pull ubuntu下载: image-20210916170616264

5.2.2 启动容器

以下命令使用 ubuntu 镜像启动一个容器,参数表示以命令行模式进入该容器:

1
docker run -it ubuntu /bin/bash

image-20210916170903084

参数说明:

  • -i: 交互式操作。
  • -t: 终端。
  • ubuntu: ubuntu 镜像。
  • /bin/bash:放在镜像名后的是命令,这里需要使用交互式方式Shell访问容器,因此用的是 /bin/bash。

要退出终端,直接输入 exit或使用快捷键Ctrl + D: image-20210916170949813

5.2.3 启动已停止运行的容器

查看所有的容器命令如下:

1
docker ps -a

image-20210916171238672

注意docker ps命令只显示当前正在运行的容器,-a选项表示显示所有容器,包括停止运行的容器。

从 Status 一列中可以看出容器 c0030ca3df6b已处于停止运行状态。

使用 docker start 启动一个已停止的容器:

1
docker start c0030ca3df6b

image-20210916171450273

可以看出,容器 c0030ca3df6b已顺利启动。

5.2.4 后台运行

在大部分的场景下,docker 的服务是在后台运行的,可以通过 -d 指定容器的运行模式。

1
docker run -itd --name ubuntu_test ubuntu /bin/bash

image-20210916171657871

注意:加了 -d 参数默认不会进入容器,可通过 docker exec命令进入容器(后续详细介绍)。

5.2.5 停止和重启一个容器

停止容器的命令为:docker stop <容器 ID>

重启容器的命令为:docker restart <容器 ID>

示例如下:

1
2
docker stop c0030ca3df6b
docker restart c0030ca3df6b

image-20210916172204941 除了docker start外,停止的容器也可以通过命令docker restart <容器 ID>重启。

5.2.6 进入容器

在使用 -d 参数时,容器启动后会在后台运行。此时想要进入容器,可通过以下命令进入:

1
2
docker attach
docker exec

推荐使用 docker exec 命令,因为使用该命令退出容器终端后,不会导致容器停止运行。

  • attach 命令

    下面演示了 docker attach 命令的使用。

    1
    
    docker attach 8708d8e65f03
    

    image-20210916172719825 可以看出,使用 docker attach 命令进入容器后,如果从该容器退出,会导致容器停止运行。

  • exec 命令

    下面演示了 docker exec 命令的使用。

    1
    
    docker exec -it 8708d8e65f03 /bin/bash
    

    image-20210916172859119 可以看出,使用docker exec命令进入容器后,从容器退出不会导致容器停止运行。因此,推荐使用docker exec命令。

    请使用docker exec --help命令查看docker exec命令的更多参数说明。

5.2.7 导出和导入容器

  • 导出容器

    如果要导出本地某个容器,可以使用 docker export 命令。

    1
    2
    
    docker export 8708d8e65f03 -o ubuntu_test.tar
    ls -l ubuntu_test.tar 
    

    image-20210916173241017

    导出容器 8708d8e65f03快照到本地文件 ubuntu_test.tar ,从上图中可以看出生成了文件 ubuntu_test.tar 。

  • 导入容器

    可以使用 docker import 从容器快照文件中再导入为镜像,以下命令将快照文件 ubuntu_test.tar 导入为镜像 cg/my_ubuntu:v1:

    1
    
    docker import ubuntu_test.tar cg/my_ubuntu:v1.0
    

    image-20210916173434471 此外,也可以通过指定 URL 或者某个目录来导入,例如:

    1
    
    docker import http://example.com/exampleimage.tar example/imagerepo
    

5.2.8 删除容器

删除容器使用 docker rm 命令:

1
docker rm 8708d8e65f03

image-20210916173654416 可见通过 docker rm 删除容器8708d8e65f03后,在容器列表中已经移除了该容器。

通过 docker container prune 命令可将处于终止状态的容器全部删除。

以下操作演示了该命令的使用,首先使用 ubuntu 镜像创建三个容器,并将其终止, image-20210916173849382 然后使用docker container prune删除停止的容器,操作如下: image-20210916173944836

1
2
3
docker ps -a
docker container prune
docker ps -a

首先使用 docker ps -a 查看所有容器状态,可以看到ubuntu_test1、ubuntu_test2、ubuntu_test3这三个容器都已经处于终止状态。

docker container prune 命令执行后,再使用 docker ps -a 查看,可以发现ubuntu_test1、ubuntu_test2、ubuntu_test3这三个容器都已删除。

注意:实验环境中还存在一个已经停止运行的hello-world容器,该容器也被 docker container prune 命令删除。这个hello-world容器是运行其他实验时遗留的容器,如果你的环境中不存在该容器也不用担心。

5.3 运行Web应用

前面运行的容器并没有特别的用处。

接下来尝试使用 docker 构建一个 web 应用程序。

5.3.1 实战环境准备

本次实战中,将在 docker 容器中基于 Python Flask 运行一个简单的web应用。

本实验项目的目录为: D:\Users\JOJO\Desktop\Docker实验报告\webapp,所需运行的程序的目录为D:\Users\JOJO\Desktop\Docker实验报告\webapp\webapp。因此,首先将工作目录切换为该目录,

1
2
3
cd /d/users/JOJO/Desktop/Docker实验报告/webapp/webapp/
pwd
ls

image-20210923200434548

使用 docker pull 命令下载webapp镜像,webapp镜像中封装了Python Flask环境,

1
docker pull training/webapp

image-20210923194709773 本应用的逻辑实现位于app.py文件中,本应用的目的是在浏览器的页面上输出:Hello World,app.py的代码内容如下: image-20210923200558597 使用webapp容器运行应用, image-20210923200858559 参数说明:

  • -d:让容器在后台运行。
  • -P:将容器内部使用的网络端口映射到宿主机上。

5.3.2 查看WEB应用容器

使用 docker ps 来查看正在运行的容器:

1
docker ps 

image-20210923201106465 可以看出,这里多了端口信息,

1
2
PORTS
0.0.0.0:32768->5000/tcp

Docker 开放了 5000 端口(默认 Python Flask 端口)映射到主机端口 32768 上。

这时可以通过浏览器访问WEB应用,在地址栏输入:localhost:32768,可以看到如下图所示的页面,

也可以在docker环境的终端内输入`curl localhost:32768`获取网页源码

image-20210923202922142 在页面上显示了 Hello world!

也可以通过 -p 参数指定所要映射的端口,

1
docker run -d -p 5000:5000 training/webapp python app.py

image-20210923203105353 docker ps查看正在运行的容器 image-20210923203230145 可以看到,容器内部的 5000 端口映射到本地主机的 5000 端口上。

在浏览器中,使用5000端口访问服务: image-20210923203315200

5.3.3 网络端口的快捷方式

通过 docker ps 命令可以查看到容器的端口映射,docker 还提供了另一个快捷方式 docker port,使用 docker port 可以查看指定 (ID 或者名字)容器的某个确定端口映射到宿主机的端口号。

上面创建的 web 应用容器 ID 为 e0c8a4a24e7e 名字为 musing_meninsky。

可以使用 docker port e0c8a4a24e7e docker port musing_meninsky 来查看容器端口的映射情况。 image-20210923203615779

5.3.4 查看WEB应用程序日志

docker logs [ID或者名字] 可以查看容器内部的标准输出。

1
2
docker logs e0c8a4a24e7e
docker logs musing_meninsky

image-20210923203744019 可以使用 -f 选项,这样 docker logs 会像 tail -f 一样来输出容器内部的标准输出。

1
2
docker logs -f e0c8a4a24e7e
docker logs -f musing_meninsky

image-20210923203919240 按CTRL+C可退出该命令。

从上面,可以看到应用程序使用的是 5000 端口并且能够查看到应用程序的访问日志。

5.3.5 查看WEB应用程序容器的进程

使用 docker top 查看容器内部运行的进程

1
docker top e0c8a4a24e7e

image-20210923204019771

5.3.6 检查WEB应用程序

使用 docker inspect 查看 Docker 的底层信息,该命令会返回一个记录了 Docker 容器配置和状态信息的JSON 文件。 image-20210923204139638

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
JOJO@DESKTOP-LG5R18D MINGW64 /d/users/JOJO/Desktop/Docker实验报告/webapp/webapp
$ docker inspect e0c8a4a24e7e
[
    {
        "Id": "e0c8a4a24e7e6b65c1c440520e49505dbe6df7fc70ada0a599e7f94280a569e9",
        "Created": "2021-09-23T12:30:47.84475838Z",
        "Path": "python",
        "Args": [
            "app.py"
        ],
        "State": {
            "Status": "running",
            "Running": true,
            "Paused": false,
            "Restarting": false,
            "OOMKilled": false,
            "Dead": false,
            "Pid": 11388,
            "ExitCode": 0,
            "Error": "",
            "StartedAt": "2021-09-23T12:30:48.014015659Z",
            "FinishedAt": "0001-01-01T00:00:00Z"
        },
        "Image": "sha256:6fae60ef344644649a39240b94d73b8ba9c67f898ede85cf8e947a887b3e6557",
        "ResolvConfPath": "/mnt/sda1/var/lib/docker/containers/e0c8a4a24e7e6b65c1c440520e49505dbe6df7fc70ada0a599e7f94280a569e9/resolv.conf",
        "HostnamePath": "/mnt/sda1/var/lib/docker/containers/e0c8a4a24e7e6b65c1c440520e49505dbe6df7fc70ada0a599e7f94280a569e9/hostname",
        "HostsPath": "/mnt/sda1/var/lib/docker/containers/e0c8a4a24e7e6b65c1c440520e49505dbe6df7fc70ada0a599e7f94280a569e9/hosts",
        "LogPath": "/mnt/sda1/var/lib/docker/containers/e0c8a4a24e7e6b65c1c440520e49505dbe6df7fc70ada0a599e7f94280a569e9/e0c8a4a24e7e6b65c1c440520e49505dbe6df7fc70ada0a599e7f94280a569e9-json.log",
        "Name": "/musing_meninsky",
        "RestartCount": 0,
        "Driver": "overlay2",
        "Platform": "linux",
        "MountLabel": "",
        "ProcessLabel": "",
        "AppArmorProfile": "",
        "ExecIDs": null,
        "HostConfig": {
            "Binds": null,
            "ContainerIDFile": "",
            "LogConfig": {
                "Type": "json-file",
                "Config": {}
            },
            "NetworkMode": "default",
            "PortBindings": {
                "5000/tcp": [
                    {
                        "HostIp": "",
                        "HostPort": "5000"
                    }
                ]
            },
            "RestartPolicy": {
                "Name": "no",
                "MaximumRetryCount": 0
            },
            "AutoRemove": false,
            "VolumeDriver": "",
            "VolumesFrom": null,
            "CapAdd": null,
            "CapDrop": null,
            "Capabilities": 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": [
                23,
                96
            ],
            "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,
            "DeviceRequests": null,
            "KernelMemory": 0,
            "KernelMemoryTCP": 0,
            "MemoryReservation": 0,
            "MemorySwap": 0,
            "MemorySwappiness": null,
            "OomKillDisable": false,
            "PidsLimit": null,
            "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": "/mnt/sda1/var/lib/docker/overlay2/972dfe028e55bd1376246a20a9482bc770110f1bfd5b8973a5c827140d86802c-init/diff:/mnt/sda1/var/lib/docker/overlay2/b255bb29042700e8d435dbb1f22d38da1e1abb5c47511689101d1f68f0fbd53d/diff:/mnt/sda1/var/lib/docker/overlay2/0df1f40ab5098ca51f98059e1cfad94b929c2d4cbded7f608ffc69572696622b/diff:/mnt/sda1/var/lib/docker/overlay2/e64a810f17657ae460453a6fcdd83d8774df17c1448ad9c66b7dc73df727ebde/diff:/mnt/sda1/var/lib/docker/overlay2/b3a8dd02542a23d08b30d185713f878ee32ec1916529affc0a5143e6d8cbaf1d/diff:/mnt/sda1/var/lib/docker/overlay2/795f0a493cb34a8272c81ba76dcbb0ae363ca7bea37c12503b7e630790eb38b9/diff:/mnt/sda1/var/lib/docker/overlay2/c9b5c8cc15c32e2dade7c934473ec334be4f026c2e263cade46872fcfc1fedcb/diff:/mnt/sda1/var/lib/docker/overlay2/90f62154c24acbb8c522025b703135de9b1a5d0545c22a3264846b42319287b8/diff:/mnt/sda1/var/lib/docker/overlay2/283683f52c3b31af68a0b04d24e8f82717471e7b33121df5046b9d8b72b0c5e6/diff:/mnt/sda1/var/lib/docker/overlay2/95f5c4414e13e6d7748649f1f208d16dad067f22e519a378e2028efb4d6d34b4/diff:/mnt/sda1/var/lib/docker/overlay2/2323ad95c0fe0a348196de058751db41b7ad901f47f709dc099631f50b33cdf1/diff:/mnt/sda1/var/lib/docker/overlay2/7de49640d3651d0f4c336dbd4d133e3612e6ad405223bd8c82f7b80eceb04e87/diff:/mnt/sda1/var/lib/docker/overlay2/1a55a67dc9f63fbb00e3943be30a42724437c9982377f65df821f67b3c6f8f93/diff:/mnt/sda1/var/lib/docker/overlay2/4ffcb6d0da325d8dddd818d76e1155e891d1a0577cfe13fd987eab089643a856/diff",
                "MergedDir": "/mnt/sda1/var/lib/docker/overlay2/972dfe028e55bd1376246a20a9482bc770110f1bfd5b8973a5c827140d86802c/merged",
                "UpperDir": "/mnt/sda1/var/lib/docker/overlay2/972dfe028e55bd1376246a20a9482bc770110f1bfd5b8973a5c827140d86802c/diff",
                "WorkDir": "/mnt/sda1/var/lib/docker/overlay2/972dfe028e55bd1376246a20a9482bc770110f1bfd5b8973a5c827140d86802c/work"
            },
            "Name": "overlay2"
        },
        "Mounts": [],
        "Config": {
            "Hostname": "e0c8a4a24e7e",
            "Domainname": "",
            "User": "",
            "AttachStdin": false,
            "AttachStdout": false,
            "AttachStderr": false,
            "ExposedPorts": {
                "5000/tcp": {}
            },
            "Tty": false,
            "OpenStdin": false,
            "StdinOnce": false,
            "Env": [
                "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
            ],
            "Cmd": [
                "python",
                "app.py"
            ],
            "Image": "training/webapp",
            "Volumes": null,
            "WorkingDir": "/opt/webapp",
            "Entrypoint": null,
            "OnBuild": null,
            "Labels": {}
        },
        "NetworkSettings": {
            "Bridge": "",
            "SandboxID": "d6d5a236e2a3ec3a2e2008fb2d1b2d1f35118700d52e3f95a1b7cc5c4d92960b",
            "HairpinMode": false,
            "LinkLocalIPv6Address": "",
            "LinkLocalIPv6PrefixLen": 0,
            "Ports": {
                "5000/tcp": [
                    {
                        "HostIp": "0.0.0.0",
                        "HostPort": "5000"
                    }
                ]
            },
            "SandboxKey": "/var/run/docker/netns/d6d5a236e2a3",
            "SecondaryIPAddresses": null,
            "SecondaryIPv6Addresses": null,
            "EndpointID": "ae4b5cd5a75d8da238d11b88170502cfe470c8e94c7e43fd579d511fda5f7bc7",
            "Gateway": "172.17.0.1",
            "GlobalIPv6Address": "",
            "GlobalIPv6PrefixLen": 0,
            "IPAddress": "172.17.0.3",
            "IPPrefixLen": 16,
            "IPv6Gateway": "",
            "MacAddress": "02:42:ac:11:00:03",
            "Networks": {
                "bridge": {
                    "IPAMConfig": null,
                    "Links": null,
                    "Aliases": null,
                    "NetworkID": "cb9d9c850475238f06e71782b77510ae854f27c26da12f562622fb6a0d1f61d0",
                    "EndpointID": "ae4b5cd5a75d8da238d11b88170502cfe470c8e94c7e43fd579d511fda5f7bc7",
                    "Gateway": "172.17.0.1",
                    "IPAddress": "172.17.0.3",
                    "IPPrefixLen": 16,
                    "IPv6Gateway": "",
                    "GlobalIPv6Address": "",
                    "GlobalIPv6PrefixLen": 0,
                    "MacAddress": "02:42:ac:11:00:03",
                    "DriverOpts": null
                }
            }
        }
    }
]

5.3.7 停止WEB应用容器

使用docker stop停止应用,

1
2
docker stop e0c8a4a24e7e
docker ps

image-20210923204429354 可以看到该容器已停止。

再次使用浏览器访问, image-20210923204509187 可以发现服务已经停止运行。

5.3.8 重启WEB应用容器

可通过docker start <容器ID> 或者 docker restart <容器ID>启动停止运行的容器,已经停止的容器,可以使用命令 docker start 来启动。 image-20210923204908965 容器启动后,再次使用浏览器访问Web服务: image-20210923205022493 可见,服务已经可以正常访问。

可以使用命令 docker ps -l 查询最后一次创建的容器: image-20210923205054851

5.3.9 移出WEB应用容器

可使用 docker rm 命令删除容器,例如对于容器e0c8a4a24e7e,

1
2
3
docker rm e0c8a4a24e7e
docker stop e0c8a4a24e7e
docker rm e0c8a4a24e7e

image-20210923205243079 删除容器时,容器必须是停止状态,否则会报错。

本文由作者按照 CC BY 4.0 进行授权