• Docker 管理命令
    • 容器管理
    • 镜像管理
    • 网络管理
    • 系统管理
    • 数据卷管理
    • 快照管理
    • 插件管理
    • 其他
    • swarmkit 管理
      • 模式管理
      • 节点管理
      • 秘钥管理
      • 服务管理
      • 服务栈管理

Docker 的每一级命令都可以使用--help 的参数来查看帮助信息

Docker 一级命令

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
root@ubuntu:~# docker --help

Usage: docker COMMAND

A self-sufficient runtime for containers

Options:
--config string Location of client config files (default "/root/.docker")
-D, --debug Enable debug mode
--help Print usage
-H, --host list Daemon socket(s) to connect to (default [])
-l, --log-level string Set the logging level ("debug"|"info"|"warn"|"error"|"fatal") (default "info")
--tls Use TLS; implied by --tlsverify
--tlscacert string Trust certs signed only by this CA (default "/root/.docker/ca.pem")
--tlscert string Path to TLS certificate file (default "/root/.docker/cert.pem")
--tlskey string Path to TLS key file (default "/root/.docker/key.pem")
--tlsverify Use TLS and verify the remote
-v, --version Print version information and quit

Management Commands:
container Manage containers
image Manage images
network Manage networks
node Manage Swarm nodes
plugin Manage plugins
secret Manage Docker secrets
service Manage services
stack Manage Docker stacks
swarm Manage Swarm
system Manage Docker
volume Manage volumes

Commands:
attach Attach to a running container
build Build an image from a Dockerfile
commit Create a new image from a container's changes
cp Copy files/folders between a container and the local filesystem
create Create a new container
diff Inspect changes to files or directories on a container's filesystem
events Get real time events from the server
exec Run a command in a running container
export Export a container's filesystem as a tar archive
history Show the history of an image
images List images
import Import the contents from a tarball to create a filesystem image
info Display system-wide information
inspect Return low-level information on Docker objects
kill Kill one or more running containers
load Load an image from a tar archive or STDIN
login Log in to a Docker registry
logout Log out from a Docker registry
logs Fetch the logs of a container
pause Pause all processes within one or more containers
port List port mappings or a specific mapping for the container
ps List containers
pull Pull an image or a repository from a registry
push Push an image or a repository to a registry
rename Rename a container
restart Restart one or more containers
rm Remove one or more containers
rmi Remove one or more images
run Run a command in a new container
save Save one or more images to a tar archive (streamed to STDOUT by default)
search Search the Docker Hub for images
start Start one or more stopped containers
stats Display a live stream of container(s) resource usage statistics
stop Stop one or more running containers
tag Create a tag TARGET_IMAGE that refers to SOURCE_IMAGE
top Display the running processes of a container
unpause Unpause all processes within one or more containers
update Update configuration of one or more containers
version Show the Docker version information
wait Block until one or more containers stop, then print their exit codes

Run 'docker COMMAND --help' for more information on a command.

在 Docker1.13版本之前, 是没有二级管理命令的, 随着 Docker 的功能越来越多, 命令参数也越来越多, 到1.13版本后, Docker 终于对他们做出了归类, 之前的语法也兼容, 但是 Docker 推荐使用最新的语法格式.

1.13版本后, Docker 对命令做出了如下归类:

  • container Manage containers
  • image Manage images
  • network Manage networks
  • node Manage Swarm nodes
  • plugin Manage plugins
  • secret Manage Docker secrets
  • service Manage services
  • stack Manage Docker stacks
  • swarm Manage Swarm
  • system Manage Docker
  • volume Manage volumes

容器管理 container

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
root@ubuntu:~# docker container --help

Usage: docker container COMMAND

Manage containers

Options:
--help Print usage

Commands:
attach Attach to a running container
commit Create a new image from a container's changes
cp Copy files/folders between a container and the local filesystem
create Create a new container
diff Inspect changes to files or directories on a container's filesystem
exec Run a command in a running container
export Export a container's filesystem as a tar archive
inspect Display detailed information on one or more containers
kill Kill one or more running containers
logs Fetch the logs of a container
ls List containers
pause Pause all processes within one or more containers
port List port mappings or a specific mapping for the container
prune Remove all stopped containers
rename Rename a container
restart Restart one or more containers
rm Remove one or more containers
run Run a command in a new container
start Start one or more stopped containers
stats Display a live stream of container(s) resource usage statistics
stop Stop one or more running containers
top Display the running processes of a container
unpause Unpause all processes within one or more containers
update Update configuration of one or more containers
wait Block until one or more containers stop, then print their exit codes

Run 'docker container COMMAND --help' for more information on a command.

attach

进入容器的方式之一, 翻译过来叫”附着”到运行的容器中. 他与exec 有本质的区别, exec 进入容器是在主进程的基础之上, 再开通一个进程实现的进入容器. 而 attach 则意味着进入到容器的主进程中. 产生的后果也不一样, 由于 attach 进入到了主进程, 一旦 Ctrl+C 退出终端, 将导致主进程退出, 从而容器也随之退出. 而 exec 的方式进入容器是单独开启了一个进程, 该进程的产生于销毁并不影响主进程, 所以不会因为终端的退出而导致容器退出.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
root@ubuntu:~# docker run -d centos ping 123.57.233.243
2ad157c779469961faabec0e836f7d2ab03a7e6193d932647e83626231fa0560
root@ubuntu:~#
root@ubuntu:~# docker container attach 2ad
64 bytes from 123.57.233.243: icmp_seq=40 ttl=127 time=8.05 ms
64 bytes from 123.57.233.243: icmp_seq=41 ttl=127 time=7.46 ms
64 bytes from 123.57.233.243: icmp_seq=42 ttl=127 time=8.86 ms
64 bytes from 123.57.233.243: icmp_seq=43 ttl=127 time=9.80 ms
64 bytes from 123.57.233.243: icmp_seq=44 ttl=127 time=6.24 ms
64 bytes from 123.57.233.243: icmp_seq=45 ttl=127 time=6.01 ms
^C
--- 123.57.233.243 ping statistics ---
62 packets transmitted, 62 received, 0% packet loss, time 61130ms
rtt min/avg/max/mdev = 5.407/18.181/204.154/32.140 ms
root@ubuntu:~#

exec

在一个运行中的容器内执行命令. 就如上面所说, 使用 exec 执行命令意味着在主进程的基础之上, 再启动其他的进程, 其他进程的启动与销毁不会直接影响容器的退出.

exec 的用法很多, 使用频率最高的是进入容器的操作

1
2
root@ubuntu:~# docker container exec -it b9704931408c /bin/bash
root@b9704931408c:/#

也可以运行任何bash命令

1
2
3
4
5
6
7
root@ubuntu:~# docker container exec 11610baab1ce echo "haha"
haha
root@ubuntu:~# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b9704931408c nginx "nginx -g 'daemon ..." About an hour ago Up About an hour 0.0.0.0:443->443/tcp, 0.0.0.0:8080->80/tcp my-third-nginx
d0a4936e940e nginx "nginx -g 'daemon ..." About an hour ago Up About an hour 443/tcp, 0.0.0.0:8800->80/tcp my-second-nginx
11610baab1ce nginx "nginx -g 'daemon ..." About an hour ago Up 12 minutes 80/tcp, 443/tcp my-first-nginx

commit

基于一个现有的容器创建新的镜像. commit 多用在做容器迁移的时候, 当容器为由状态时, 我们需要保存现有容器的所有运行状态以保证迁移后的一致性, 这时 commit 就派上了用场.

运行一个初始的镜像, 我们通过 exec 进入到容器, 并做了一些修改, 当需要迁移此容器时, 可以把当前修改过后的容器保存为一个新的镜像. 然后将镜像迁移至新主机, 再 run 起来.

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
# 修改容器内容
root@ubuntu:~# docker exec -it my-first-nginx /bin/bash
root@11610baab1ce:/# cd /tmp/
root@11610baab1ce:/tmp# ls
root@11610baab1ce:/tmp# echo "commit test" > /tmp/c.txt
root@11610baab1ce:/tmp# ls
c.txt
root@11610baab1ce:/tmp# cat /tmp/c.txt
commit test
root@11610baab1ce:/tmp# exit
exit
# commit 镜像
root@ubuntu:~# docker commit my-first-nginx nginx2:0.1
sha256:7cb5220c81d58a56471b6ce69e40bf4d15f89652b4b4bd78ec4579b6473bfc91
root@ubuntu:~# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx2 0.1 7cb5220c81d5 4 seconds ago 204MB
centos latest a8493f5f50ff 35 hours ago 192MB
nginx latest 5766334bdaa0 39 hours ago 183MB
hello-world latest 48b5124b2768 2 months ago 1.84kB
# 基于新镜像运行新容器
root@ubuntu:~# docker exec -it new-first-nginx /bin/bash
root@b4e6f8620ba3:/# cd /tmp/
root@b4e6f8620ba3:/tmp# ls
c.txt
root@b4e6f8620ba3:/tmp# cat c.txt
commit test
root@b4e6f8620ba3:/tmp#

注意: 挂载的数据是不会被 commit 到镜像中的. 迁移之后需要用相同的参数启动起来

迁移有两种方式:

  • 一种是导入导出的方式(通过 tar.gz 文件)
  • 一种是通过 Registry 的方式 push 和 pull

如果是通过 Registry 的方式的话, 需要在 commit 时, 镜像名字中加入 Registry 地址

docker container commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]

注意: commit 的过程中, 容器处于 pause 的状态, 类似于 MySQL 的排它锁

cp

通过 cp 命令可以把容器中的文件拷贝到宿主机(把文件拿出来)

1
2
3
4
5
6
7
8
9
10
11
12
13
root@ubuntu:~# docker container cp --help

Usage: docker container cp [OPTIONS] CONTAINER:SRC_PATH DEST_PATH|-
docker cp [OPTIONS] SRC_PATH|- CONTAINER:DEST_PATH

Copy files/folders between a container and the local filesystem

Options:
-L, --follow-link Always follow symbol link in SRC_PATH
--help Print usage
root@ubuntu:~# docker container cp my-first-nginx:/tmp/c.txt ./
root@ubuntu:~# ls
c.txt web

注意: 两种执行方式的语法不同

diff

列出与原始镜像相比,容器中变化的内容.

  • A: 增加
  • D: 删除
  • C: 修改
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
root@ubuntu:~# docker container diff  --help

Usage: docker container diff CONTAINER

Inspect changes to files or directories on a container's filesystem

Options:
--help Print usage
root@ubuntu:~# docker container diff my-second-nginx
C /run
A /run/nginx.pid
C /var
C /var/cache
C /var/cache/nginx
A /var/cache/nginx/client_temp
A /var/cache/nginx/fastcgi_temp
A /var/cache/nginx/proxy_temp
A /var/cache/nginx/scgi_temp
A /var/cache/nginx/uwsgi_temp

export&import/save&load

Docker 的导入导出

https://docs.lvrui.io/2017/02/19/docker的导入导出/

export&import 操作的对象是容器, 导出到一个新的镜像, 该镜像只有一层

save&load 操作对象是镜像, 原镜像层数保留

如果导出容器还需要保留层数, 那就需要使用 commit+save+load 黄金组合啦

inspect

查看容器详细信息

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
root@ubuntu:~# docker container inspect my-third-nginx
[
{
"Id": "b9704931408c6d054bc9c510878e10467a71d412bef065afa7414403982001b6",
"Created": "2017-04-08T06:22:29.186834559Z",
"Path": "nginx",
"Args": [
"-g",
"daemon off;"
],
"State": {
"Status": "running",
"Running": true,
"Paused": false,
"Restarting": false,
"OOMKilled": false,
"Dead": false,
"Pid": 2648,
"ExitCode": 0,
"Error": "",
"StartedAt": "2017-04-08T06:22:29.555131293Z",
"FinishedAt": "0001-01-01T00:00:00Z"
},
"Image": "sha256:5766334bdaa0bc37f1f0c02cb94c351f9b076bcffa042d6ce811b0fd9bc31f3b",
"ResolvConfPath": "/var/lib/docker/containers/b9704931408c6d054bc9c510878e10467a71d412bef065afa7414403982001b6/resolv.conf",
"HostnamePath": "/var/lib/docker/containers/b9704931408c6d054bc9c510878e10467a71d412bef065afa7414403982001b6/hostname",
"HostsPath": "/var/lib/docker/containers/b9704931408c6d054bc9c510878e10467a71d412bef065afa7414403982001b6/hosts",
"LogPath": "/var/lib/docker/containers/b9704931408c6d054bc9c510878e10467a71d412bef065afa7414403982001b6/b9704931408c6d054bc9c510878e10467a71d412bef065afa7414403982001b6-json.log",
"Name": "/my-third-nginx",
"RestartCount": 0,
"Driver": "aufs",
"MountLabel": "",
"ProcessLabel": "",
"AppArmorProfile": "docker-default",
"ExecIDs": null,
"HostConfig": {
"Binds": [
"/root/web:/usr/share/nginx/html:ro"
],
"ContainerIDFile": "",
"LogConfig": {
"Type": "json-file",
"Config": {}
},
"NetworkMode": "default",
"PortBindings": {
"443/tcp": [
{
"HostIp": "",
"HostPort": "443"
}
],
"80/tcp": [
{
"HostIp": "",
"HostPort": "8080"
}
]
},
"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": "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": [],
"DeviceCgroupRules": null,
"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": {
"Data": null,
"Name": "aufs"
},
"Mounts": [
{
"Type": "bind",
"Source": "/root/web",
"Destination": "/usr/share/nginx/html",
"Mode": "ro",
"RW": false,
"Propagation": ""
}
],
"Config": {
"Hostname": "b9704931408c",
"Domainname": "",
"User": "",
"AttachStdin": false,
"AttachStdout": false,
"AttachStderr": false,
"ExposedPorts": {
"443/tcp": {},
"80/tcp": {}
},
"Tty": false,
"OpenStdin": false,
"StdinOnce": false,
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
"NGINX_VERSION=1.11.13-1~jessie"
],
"Cmd": [
"nginx",
"-g",
"daemon off;"
],
"ArgsEscaped": true,
"Image": "nginx",
"Volumes": null,
"WorkingDir": "",
"Entrypoint": null,
"OnBuild": null,
"Labels": {}
},
"NetworkSettings": {
"Bridge": "",
"SandboxID": "916a8bef0178b4e8e2ff1c246a9e04c85686b8ddf8493946de7103577ff8158b",
"HairpinMode": false,
"LinkLocalIPv6Address": "",
"LinkLocalIPv6PrefixLen": 0,
"Ports": {
"443/tcp": [
{
"HostIp": "0.0.0.0",
"HostPort": "443"
}
],
"80/tcp": [
{
"HostIp": "0.0.0.0",
"HostPort": "8080"
}
]
},
"SandboxKey": "/var/run/docker/netns/916a8bef0178",
"SecondaryIPAddresses": null,
"SecondaryIPv6Addresses": null,
"EndpointID": "7a9c71aae5980ccd513c1e7a4e8cefaf56a87e1d796669bbfb70ffc728d1e0bb",
"Gateway": "172.17.0.1",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"IPAddress": "172.17.0.4",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"MacAddress": "02:42:ac:11:00:04",
"Networks": {
"bridge": {
"IPAMConfig": null,
"Links": null,
"Aliases": null,
"NetworkID": "26d72edf89c3ae77e1de636d4357b819a12c24ae64ab0da4d9b2d43610c44f24",
"EndpointID": "7a9c71aae5980ccd513c1e7a4e8cefaf56a87e1d796669bbfb70ffc728d1e0bb",
"Gateway": "172.17.0.1",
"IPAddress": "172.17.0.4",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"MacAddress": "02:42:ac:11:00:04"
}
}
}
}
]

ls/ps/list

查看 container 列表

  • docker ps
  • docker container ls
  • docker container list

以上三条命令的用法和作用都是一样的, 之间做了别名

最实用的参数-s 可以显示出容器占用空间大小, 括号中的是镜像大小, 前面是可写层(容器)大小

1
2
3
4
5
6
7
root@ubuntu:~# docker container list -s
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES SIZE
b4e6f8620ba3 nginx2:0.1 "nginx -g 'daemon ..." 29 minutes ago Up 29 minutes 80/tcp, 443/tcp new-first-nginx 413B (virtual 204MB)
b9704931408c nginx "nginx -g 'daemon ..." 2 hours ago Up 2 hours 0.0.0.0:443->443/tcp, 0.0.0.0:8080->80/tcp my-third-nginx 7B (virtual 183MB)
d0a4936e940e nginx "nginx -g 'daemon ..." 2 hours ago Up 2 hours 443/tcp, 0.0.0.0:8800->80/tcp my-second-nginx 2B (virtual 183MB)
11610baab1ce nginx "nginx -g 'daemon ..." 2 hours ago Up About an hour 80/tcp, 443/tcp my-first-nginx 21.3MB (virtual 204MB)
root@ubuntu:~#

logs

查看容器的前台回显日志. 由于容器必须以阻塞前台的方式运行, 那么我们就可以通过 logs 命令来查看容器前台的回显(在默认是 json-file 日志引擎下)

1
2
3
4
5
6
7
8
9
10
11
12
root@ubuntu:~# docker run -d centos ping 123.57.233.243
791a4ad7ffa83f81a78e2bba1a5d5366a099be443beb19f66ee0d51e83cd020d
root@ubuntu:~#
root@ubuntu:~#
root@ubuntu:~# docker logs -f 791a4ad7ffa8
PING 123.57.233.243 (123.57.233.243) 56(84) bytes of data.
64 bytes from 123.57.233.243: icmp_seq=1 ttl=127 time=7.89 ms
64 bytes from 123.57.233.243: icmp_seq=2 ttl=127 time=6.66 ms
64 bytes from 123.57.233.243: icmp_seq=3 ttl=127 time=6.55 ms
64 bytes from 123.57.233.243: icmp_seq=4 ttl=127 time=6.46 ms
64 bytes from 123.57.233.243: icmp_seq=5 ttl=127 time=175 ms
64 bytes from 123.57.233.243: icmp_seq=6 ttl=127 time=267 ms

kill/start/stop/restart/rm/pause/unpause/prune

  • kill 给容器发送 kill 信号, 非正常退出容器
  • start 启动退出状态的容器
  • stop 退出运行状态的容器
  • restart 重启容器
  • rm 删除退出状态的容器
  • pause 暂停运行中的容器(处于阻塞状态)
  • unpause 恢复暂停的容器至运行状态
  • prune 删除所有 stopped 状态的容器(1.13的新特性, 救世主!)

port

查看端口的映射关系

1
2
3
4
5
6
7
8
root@ubuntu:~# docker container port my-third-nginx
443/tcp -> 0.0.0.0:443
80/tcp -> 0.0.0.0:8080
root@ubuntu:~# docker container port my-second-nginx
80/tcp -> 0.0.0.0:8800
root@ubuntu:~# docker container port my-first-nginx
root@ubuntu:~# docker container port my-second-nginx 80/tcp
0.0.0.0:8800

rename

更改容器名称

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
root@ubuntu:~# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b4e6f8620ba3 nginx2:0.1 "nginx -g 'daemon ..." About an hour ago Up About an hour 80/tcp, 443/tcp new-first-nginx
b9704931408c nginx "nginx -g 'daemon ..." 2 hours ago Up 2 hours 0.0.0.0:443->443/tcp, 0.0.0.0:8080->80/tcp my-third-nginx
d0a4936e940e nginx "nginx -g 'daemon ..." 2 hours ago Up 2 hours 443/tcp, 0.0.0.0:8800->80/tcp my-second-nginx
11610baab1ce nginx "nginx -g 'daemon ..." 2 hours ago Up About an hour 80/tcp, 443/tcp my-first-nginx
root@ubuntu:~# docker container rename --help

Usage: docker container rename CONTAINER NEW_NAME

Rename a container

Options:
--help Print usage
root@ubuntu:~# docker container rename new-first-nginx new-first-nginx2
root@ubuntu:~# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b4e6f8620ba3 nginx2:0.1 "nginx -g 'daemon ..." About an hour ago Up About an hour 80/tcp, 443/tcp new-first-nginx2
b9704931408c nginx "nginx -g 'daemon ..." 2 hours ago Up 2 hours 0.0.0.0:443->443/tcp, 0.0.0.0:8080->80/tcp my-third-nginx
d0a4936e940e nginx "nginx -g 'daemon ..." 2 hours ago Up 2 hours 443/tcp, 0.0.0.0:8800->80/tcp my-second-nginx
11610baab1ce nginx "nginx -g 'daemon ..." 2 hours ago Up About an hour 80/tcp, 443/tcp my-first-nginx
root@ubuntu:~#

stats

实时查看容器资源使用状况

1
2
3
4
5
6
root@ubuntu:~# docker container stats 
CONTAINER CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
b4e6f8620ba3 0.00% 1.457MiB / 975.1MiB 0.15% 690B / 0B 0B / 4.1kB 2
b9704931408c 0.00% 1.449MiB / 975.1MiB 0.15% 732B / 0B 0B / 0B 2
d0a4936e940e 0.00% 1.512MiB / 975.1MiB 0.16% 1.36kB / 671B 0B / 0B 2
11610baab1ce 0.00% 1.465MiB / 975.1MiB 0.15% 732B / 0B 0B / 0B 2

top

查看容器的进程信息

1
2
3
4
5
6
7
8
9
10
11
12
root@ubuntu:~# docker container top --help

Usage: docker container top CONTAINER [ps OPTIONS]

Display the running processes of a container

Options:
--help Print usage
root@ubuntu:~# docker container top my-third-nginx
UID PID PPID C STIME TTY TIME CMD
root 2648 2631 0 Apr07 ? 00:00:00 nginx: master process nginx -g daemon off;
syslog 2669 2648 0 Apr07 ? 00:00:00 nginx: worker process

update

调整分配给容器的计算资源, 可以更改该容器可以使用的 CPU 计算资源与内存资源等

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
root@ubuntu:~# docker container update --help

Usage: docker container update [OPTIONS] CONTAINER [CONTAINER...]

Update configuration of one or more containers

Options:
--blkio-weight uint16 Block IO (relative weight), between 10 and 1000, or 0 to disable (default 0)
--cpu-period int Limit CPU CFS (Completely Fair Scheduler) period
--cpu-quota int Limit CPU CFS (Completely Fair Scheduler) quota
--cpu-rt-period int Limit the CPU real-time period in microseconds
--cpu-rt-runtime int Limit the CPU real-time runtime in microseconds
-c, --cpu-shares int CPU shares (relative weight)
--cpuset-cpus string CPUs in which to allow execution (0-3, 0,1)
--cpuset-mems string MEMs in which to allow execution (0-3, 0,1)
--help Print usage
--kernel-memory bytes Kernel memory limit
-m, --memory bytes Memory limit
--memory-reservation bytes Memory soft limit
--memory-swap bytes Swap limit equal to memory plus swap: '-1' to enable unlimited swap
--restart string Restart policy to apply when a container exits

wait

阻塞容器的运行直到停止为止, 然后打印该容器的退出状态码

1
2
3
4
5
6
7
8
9
10
11
# 终端1
root@ubuntu:~# docker container wait new-first-nginx2
# 终端被阻塞

# 终端2
root@ubuntu:~# docker container stop new-first-nginx2
new-first-nginx2

# 终端1
root@ubuntu:~# docker container wait new-first-nginx2
0

run

运行一个容器, 这个命令的参数非常多, 可以定制的属性也非常多, 常用参数如下

  • -e: 设置环境变量
  • -h: 设置 hostname
  • -i: 开放标准输入
  • -t: 分配伪终端
  • -l: 打标签
  • -p: 指定映射出来的端口(可随机分配, 可以指定)
  • -P: 映射容器内所有开放的端口(端口号随机分配)
  • -v: 数据卷的挂载
  • --volumes-driver: 指定存储引擎
  • -w: 容器运行的工作目录
  • --restart: 默认为 no, 容器异常退出后禁止自动重启
    • 设置为 --restart=on-failure:10 , 意味对该容器的非0退出状态进行重启, 最多重启10次
    • 设置为 --restart=always 始终重启
  • --network: 指定网络类型
  • --name: 指定容器名称
  • --log-driver: 指定日志引擎
  • --link: 网络层连通指定容器
  • --dns: 指定容器内使用的 DNS 服务器
  • --privileged: 提权,在容器内获取扩展的执行权限
  • --add-host: hosts 配置. 例如: --add-host polarsnow:123.57.233.243

  • bash 前台运行
  • 容器持久运行的条件
  • nginx 后台运行
  • 后台运行的条件
  • Docker数据存储的哲学
  • Docker使用的哲学

前台运行容器

拉取 centos 镜像

1
2
3
4
5
6
root@ubuntu:~# docker pull centos
Using default tag: latest
latest: Pulling from library/centos
93857f76ae30: Pull complete
Digest: sha256:4eda692c08e0a065ae91d74e82fff4af3da307b4341ad61fa61771cc4659af60
Status: Downloaded newer image for centos:latest

查看镜像列表

1
2
3
4
5
root@ubuntu:~# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
centos latest a8493f5f50ff 33 hours ago 192MB
nginx latest 5766334bdaa0 37 hours ago 183MB
hello-world latest 48b5124b2768 2 months ago 1.84kB

以前台运行方式运行容器

1
2
root@ubuntu:~# docker run --name "mycentos" -it centos /bin/bash
[root@e4b1ccd2600b /]#
  • run: 运行一个容器
  • —name “mycentos”: 给容器命名
  • -i: 打开容器的标准输入
  • -t: 分配一个伪终端 tty
  • centos: 镜像名
  • 运行容器后执行的命令

语法:

1
2
3
4
5
root@ubuntu:~# docker run --help

Usage: docker run [OPTIONS] IMAGE [COMMAND] [ARG...]

Run a command in a new container

操作容器

1
yum install dstat htop lsof curl wget lrzsz

退出终端/退出容器

1
2
3
[root@e4b1ccd2600b /]# 
[root@e4b1ccd2600b /]# exit
root@ubuntu:~#

随着终端的退出, 容器也随之退出


容器持久运行的条件

阻塞!!!

Docker 容器持久运行的基本条件是-进程的阻塞!

Docker 的哲学中, 主张一个容器只启动”一个进程”, 这里的一个进程可以理解为一个程序 或是一个主进程, 比如一个 Apache, 一个 Apache 可以启动一个主进程和若干个子进程.

如果想让 Docker 持久化运行, 那么在容器启动时, 必须有一个进程阻塞住终端. Docker 判断容器内服务是否正常的方式很简单, 就是判断最后阻塞的进程是否挂掉, 如果最后阻塞的进程挂掉, 那么容器退出.

Docker 认为, 容器即服务, 容器即程序, 一个容器就是一个程序, 如果一个容器内启动了多个服务, 比如 A, B 和 C服务, C 作为最后一个程序阻塞住容器使其运行起来, 此时, 如果容器内部的 A 或 B 服务挂掉, 容器仍然认为自己是正常的, 因为 Docker 只关心最后阻塞的进程是否退出. 反之, A 和 B 服务正常, 如果 C 服务挂掉, 那么则整个容器退出!


后台运行容器

获取 nginx 镜像

https://hub.docker.com

右边是拉取 nginx latest 版本镜像的命令

左边 repo info 标签内是 nginx 简短说明/完整说明

完整说明中包括:

  • 版本的介绍
  • 软件的介绍
  • 使用方式的介绍

左边 tag 是所有版本的列表

https://store.docker.com

下载最新稳定发行版的 nginx 镜像

1
2
3
4
5
6
7
8
9
10
root@ubuntu:~# docker pull nginx
Using default tag: latest
latest: Pulling from library/nginx
6d827a3ef358: Pull complete
f8f2e0556751: Pull complete
5c9972dca3fd: Pull complete
451b9524cb06: Pull complete
Digest: sha256:e6693c20186f837fc393390135d8a598a96a833917917789d63766cab6c59582
Status: Downloaded newer image for nginx:latest
root@ubuntu:~#

运行 nginx 镜像

1
2
3
4
5
6
7
8
9
10
# 首先创建一个 web 目录
root@ubuntu:~# mkdir web
root@ubuntu:~# echo "Hello Docker" > web/index.html
# 运行 nginx 镜像
root@ubuntu:~# docker run --name "my-first-nginx" -v /root/web:/usr/share/nginx/html:ro -d nginx
11610baab1ce0b684367a44313fc0401489b115399f0a4469bec15bd4b8f6769
root@ubuntu:~# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
11610baab1ce nginx "nginx -g 'daemon ..." 6 seconds ago Up 6 seconds 80/tcp, 443/tcp my-first-nginx
root@ubuntu:~#
  • -v: 挂载卷 宿主机目录:容器内目录:挂载方式 其中挂载方式支持以只读ro或读写rw方式挂载, 默认为rw
  • -d: 以守护进程daemon方式放入到后台运行

此方式没有对外映射端口, 所以只能在容器内部访问

在容器内部访问页面

1
2
3
4
5
6
7
8
9
10
11
12
13
# 进入容器
root@ubuntu:~# docker exec -it 11610 /bin/bash
# 查看命令是否安装
root@11610baab1ce:/# curl
bash: curl: command not found
# 查看发行版
root@11610baab1ce:/# cat /etc/issue
Debian GNU/Linux 8 \n \l
# 安装命令
root@11610baab1ce:/# apt install curl
# 测试页面
root@11610baab1ce:/# curl http://127.0.0.1
Hello Docker

运行暴露端口的 nginx 镜像

1
2
3
4
5
6
7
8
9
root@ubuntu:~# docker run --name "my-second-nginx" -v /root/web:/usr/share/nginx/html:ro -d -p 8800:80 nginx
d0a4936e940e5d3b9e2d96be3b08133ddb7f5d9f9a28a81e3b99dff03fb1d747
root@ubuntu:~# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
d0a4936e940e nginx "nginx -g 'daemon ..." 3 seconds ago Up 2 seconds 443/tcp, 0.0.0.0:8800->80/tcp my-second-nginx
11610baab1ce nginx "nginx -g 'daemon ..." 12 minutes ago Up 12 minutes 80/tcp, 443/tcp my-first-nginx
root@ubuntu:~#
root@ubuntu:~# curl http://127.0.0.1:8800
Hello Docker
  • -p: 对外映射端口 宿主机端口:容器内端口

运行暴露多个端口的 nginx 镜像

1
2
3
4
5
6
7
8
root@ubuntu:~# docker run --name "my-third-nginx" -v /root/web:/usr/share/nginx/html:ro -d -p 8080:80 -p 443:443 nginx
b9704931408c6d054bc9c510878e10467a71d412bef065afa7414403982001b6
root@ubuntu:~# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b9704931408c nginx "nginx -g 'daemon ..." 6 seconds ago Up 6 seconds 0.0.0.0:443->443/tcp, 0.0.0.0:8080->80/tcp my-third-nginx
d0a4936e940e nginx "nginx -g 'daemon ..." 3 minutes ago Up 3 minutes 443/tcp, 0.0.0.0:8800->80/tcp my-second-nginx
11610baab1ce nginx "nginx -g 'daemon ..." 15 minutes ago Up 15 minutes 80/tcp, 443/tcp my-first-nginx
root@ubuntu:~#

Docker 数据存储的哲学

Docker 主张运行无状态的容器, 什么样的容器是无状态的容器呢?

打个比方: 以上面的 nginx 实例为例

  • 以如上方式-v挂载的方式即为有状态
  • 以 dockerfile 的形式将数据目录预先拷贝到镜像的方式即为无状态

也可以简单的理解为:

  • 镜像内包含数据且数据可随时随着镜像销毁的容器为无状态容器
  • 镜像内只包含运行环境, 数据需要靠挂载目录的, 或是容器内数据不可随意销毁的容器为有状态容器

这两种用法各有利弊, 直至现在也争论不休, 没有最好的使用方式, 只有最合适的使用方式(注意: 在集群中, 最好使用无状态的方式. 但是最新版本的 k8s 已经支持有状态容器集群)

Docker 使用的哲学

由于 Docker 容器的生命周期完全取决于最后阻塞容器入口的进程的存活状态, 所以在使用容器的时候, 一定要多加注意阻塞入口的进程和主进程的关系. 比如 node.js 容器, 在里面使用pm2 管理的 node 项目, 最后阻塞入口的进程是 pm2, 那么里面 node 项目的管理就脱离了容器的控制, 而由 pm2 去接管, 在node 进程出问题时也是由pm2去控制重启的. 在实际使用情况中, 一定要注意这样的使用方式会不会对后续的维护造成不便. 我推荐使用原生的命令启动主进程, 不要在主进程外面再套一层程序管理层.

安装命令

1
2
3
4
5
6

# 公网通用
curl -sSL http://acs-public-mirror.oss-cn-hangzhou.aliyuncs.com/docker-engine/internet | sh -

# 阿里云专用
curl -sSL http://acs-public-mirror.oss-cn-hangzhou.aliyuncs.com/docker-engine/intranet | sh -

安装完成后的结束信息:

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
root@ubuntu:~# curl -sSL http://acs-public-mirror.oss-cn-hangzhou.aliyuncs.com/docker-engine/internet | sh -
......
......
+ sh -c docker version
Client:
Version: 17.04.0-ce
API version: 1.28
Go version: go1.7.5
Git commit: 4845c56
Built: Mon Apr 3 18:07:42 2017
OS/Arch: linux/amd64

Server:
Version: 17.04.0-ce
API version: 1.28 (minimum version 1.12)
Go version: go1.7.5
Git commit: 4845c56
Built: Mon Apr 3 18:07:42 2017
OS/Arch: linux/amd64
Experimental: false

If you would like to use Docker as a non-root user, you should now consider
adding your user to the "docker" group with something like:

sudo usermod -aG docker your-user

Remember that you will have to log out and back in for this to take effect!

重点注意: sudo usermod -aG docker your-user

在 Ubuntu 系统中, 使用普通用户登录的情况很多, 如果普通用户需要直接有权限控制 docker 所有的操作的话, 需要将该普通用户加入到 docker 组中.

Docker 是 C/S 架构, 一般情况下, C 和 S 是在安装在一台主机上的, 本地的 C 控制本地的 S, 后期控制大规模 Docker 的时候, 需要开放Docker API 来远程控制 Docker Server 端

检查 Docker 运行状态

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
root@ubuntu:~# systemctl status docker
● docker.service - Docker Application Container Engine
Loaded: loaded (/lib/systemd/system/docker.service; enabled; vendor preset: enabled)
Active: active (running) since Fri 2017-04-07 20:43:48 PDT; 9min ago
Docs: https://docs.docker.com
Main PID: 4082 (dockerd)
CGroup: /system.slice/docker.service
├─4082 /usr/bin/dockerd -H fd://
└─4095 docker-containerd -l unix:///var/run/docker/libcontainerd/docker-containerd.sock --metri

Apr 07 20:43:48 ubuntu dockerd[4082]: time="2017-04-07T20:43:48.175051418-07:00" level=warning msg="Your k
Apr 07 20:43:48 ubuntu dockerd[4082]: time="2017-04-07T20:43:48.175185511-07:00" level=warning msg="Your k
Apr 07 20:43:48 ubuntu dockerd[4082]: time="2017-04-07T20:43:48.175683715-07:00" level=info msg="Loading c
Apr 07 20:43:48 ubuntu dockerd[4082]: time="2017-04-07T20:43:48.228757745-07:00" level=info msg="Firewalld
Apr 07 20:43:48 ubuntu dockerd[4082]: time="2017-04-07T20:43:48.327388388-07:00" level=info msg="Default b
Apr 07 20:43:48 ubuntu dockerd[4082]: time="2017-04-07T20:43:48.383792709-07:00" level=info msg="Loading c
Apr 07 20:43:48 ubuntu dockerd[4082]: time="2017-04-07T20:43:48.420530516-07:00" level=info msg="Daemon ha
Apr 07 20:43:48 ubuntu dockerd[4082]: time="2017-04-07T20:43:48.420807227-07:00" level=info msg="Docker da
Apr 07 20:43:48 ubuntu systemd[1]: Started Docker Application Container Engine.
Apr 07 20:43:48 ubuntu dockerd[4082]: time="2017-04-07T20:43:48.434958396-07:00" level=info msg="API liste
lines 1-19/19 (END)

操作 Docker 进程

  • 关闭 Docker 服务 systemctl stop docker
  • 重启 Docker 服务 systemctl restart docker
  • 开启 Docker 服务 systemctl start docker
  • 开机启动 Docker systemctl enable docker

检查 Docker 服务

  • Docker 服务运行正常的回显
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
root@ubuntu:~# docker info
Containers: 0
Running: 0
Paused: 0
Stopped: 0
Images: 0
Server Version: 17.04.0-ce
Storage Driver: aufs
Root Dir: /var/lib/docker/aufs
Backing Filesystem: extfs
Dirs: 0
Dirperm1 Supported: true
Logging Driver: json-file
Cgroup Driver: cgroupfs
Plugins:
Volume: local
Network: bridge host macvlan null overlay
Swarm: inactive
Runtimes: runc
Default Runtime: runc
Init Binary:
containerd version: 422e31ce907fd9c3833a38d7b8fdd023e5a76e73
runc version: 9c2d8d184e5da67c95d601382adf14862e4f2228
init version: 949e6fa
Security Options:
apparmor
seccomp
Profile: default
Kernel Version: 4.4.0-21-generic
Operating System: Ubuntu 16.04 LTS
OSType: linux
Architecture: x86_64
CPUs: 1
Total Memory: 975.1MiB
Name: ubuntu
ID: VK2Y:PFFS:OEDA:7RIL:PLF5:SA4F:RJNS:7VEF:ODLG:LX6M:OVY4:BECX
Docker Root Dir: /var/lib/docker
Debug Mode (client): false
Debug Mode (server): false
Registry: https://index.docker.io/v1/
Experimental: false
Insecure Registries:
127.0.0.0/8
Live Restore Enabled: false

WARNING: No swap limit support
  • Docker 服务运行异常的回显(普通用户如果没有加入到 docker 组中, 执行 docker 命令也会出现以下的报错)
1
2
root@ubuntu:~# docker info
Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?
  • 还有一种情况, 可能由于某些原因导致终端阻塞, 大多数情况下, 即使使用 systemctl 关闭 Docker 服务也无法正常关闭, 只能重启服务器宿主机

Docker 信息解读

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
root@ubuntu:~# docker info
Containers: 0 # 总容器数量
Running: 0 # 运行中的容器数量
Paused: 0 # 暂停的容器数量
Stopped: 0 # 停止的容器数量
Images: 0 # 总镜像数量
Server Version: 17.04.0-ce # Docker Server 版本
Storage Driver: aufs # 存储引擎
Root Dir: /var/lib/docker/aufs # 存储引擎根目录
Backing Filesystem: extfs # 后端文件系统类型
Dirs: 0 # aufs 的属性
Dirperm1 Supported: true # aufs 的属性
Logging Driver: json-file # 日志引擎
Cgroup Driver: cgroupfs # Cgroup 引擎
Plugins: # 插件信息
Volume: local # 数据卷插件
Network: bridge host macvlan null overlay # 网络插件
Swarm: inactive # swarmkit 模式状态
Runtimes: runc # 容器执行引擎
Default Runtime: runc # 默认容器执行引擎
Init Binary:
containerd version: 422e31ce907fd9c3833a38d7b8fdd023e5a76e73
runc version: 9c2d8d184e5da67c95d601382adf14862e4f2228
init version: 949e6fa
Security Options: # 安全项
apparmor # Linux内核中的强制访问控制系统
seccomp # Linux kernel(2.6.23版本之后)所支持的一种简洁的沙箱机制
Profile: default
Kernel Version: 4.4.0-21-generic # 宿主机内核版本
Operating System: Ubuntu 16.04 LTS # 宿主机系统发行版
OSType: linux # 宿主机系统类型
Architecture: x86_64 # 宿主机 CPU 架构
CPUs: 1 # 宿主机总 CPU 容量
Total Memory: 975.1MiB # 宿主机总内存容量
Name: ubuntu # 宿主机系统名称
ID: VK2Y:PFFS:OEDA:7RIL:PLF5:SA4F:RJNS:7VEF:ODLG:LX6M:OVY4:BECX
Docker Root Dir: /var/lib/docker # Docker 家目录
Debug Mode (client): false # 客户端是否开启 debug 模式
Debug Mode (server): false # 服务端是否开启 debug 模式
Registry: https://index.docker.io/v1/ # 默认仓库地址
Experimental: false # 是否是体验版 Docker(edge)
Insecure Registries: # 不安全的仓库
127.0.0.0/8
Live Restore Enabled: false # 在线恢复/热恢复

WARNING: No swap limit support # cgroups中的swap account没有开启

注意: 生产环境中, 依据自己的需要, 可以适当调整swap limit support的支持情况.

宁宕勿慢, 宁慢勿宕, 两个考量系统健壮性的思路, 没有最好的方案, 各有利弊, 需要综合自己的实际情况考量

1
2
3
4
5
6
7
8
9
10
Edit the /etc/default/grub file.
Set the GRUB_CMDLINE_LINUX value as follows:

GRUB_CMDLINE_LINUX="cgroup_enable=memory swapaccount=1"
Save and close the file.

Update GRUB.

$ sudo update-grub
Reboot your system.

运行 hello word容器

添加代理仓库-daocloud

1
2
3
4
5
6
root@ubuntu:~# curl -sSL https://get.daocloud.io/daotools/set_mirror.sh | sh -s http://172d594a.m.daocloud.io
docker version >= 1.12
{"registry-mirrors": ["http://172d594a.m.daocloud.io"]}
Success.
You need to restart docker to take effect: sudo systemctl restart docker.service
root@ubuntu:~# systemctl restart docker

查看代理信息

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
root@ubuntu:~# docker info
Containers: 0
Running: 0
Paused: 0
Stopped: 0
Images: 0
Server Version: 17.04.0-ce
Storage Driver: aufs
Root Dir: /var/lib/docker/aufs
Backing Filesystem: extfs
Dirs: 0
Dirperm1 Supported: true
Logging Driver: json-file
Cgroup Driver: cgroupfs
Plugins:
Volume: local
Network: bridge host macvlan null overlay
Swarm: inactive
Runtimes: runc
Default Runtime: runc
Init Binary:
containerd version: 422e31ce907fd9c3833a38d7b8fdd023e5a76e73
runc version: 9c2d8d184e5da67c95d601382adf14862e4f2228
init version: 949e6fa
Security Options:
apparmor
seccomp
Profile: default
Kernel Version: 4.4.0-21-generic
Operating System: Ubuntu 16.04 LTS
OSType: linux
Architecture: x86_64
CPUs: 1
Total Memory: 975.1MiB
Name: ubuntu
ID: VK2Y:PFFS:OEDA:7RIL:PLF5:SA4F:RJNS:7VEF:ODLG:LX6M:OVY4:BECX
Docker Root Dir: /var/lib/docker
Debug Mode (client): false
Debug Mode (server): false
Registry: https://index.docker.io/v1/
Experimental: false
Insecure Registries:
127.0.0.0/8
Registry Mirrors: # 镜像代理
http://172d594a.m.daocloud.io/
Live Restore Enabled: false

运行 hello-world 容器

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
root@ubuntu:~# docker run hello-world
Unable to find image 'hello-world:latest' locally # 在本地没有找到该镜像
latest: Pulling from library/hello-world # 在远程仓库中查找镜像
78445dd45222: Pull complete # 拉取镜像
Digest: sha256:c5515758d4c5e1e838e9cd307f6c6a0d620b5e07e6f927b07d05f6d12a1ac8d7
Status: Downloaded newer image for hello-world:latest # 镜像拉取完毕
# ------以下内容是运行容器时打印到屏幕的内容------
Hello from Docker!
This message shows that your installation appears to be working correctly.

To generate this message, Docker took the following steps:
1. The Docker client contacted the Docker daemon.
2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
3. The Docker daemon created a new container from that image which runs the
executable that produces the output you are currently reading.
4. The Docker daemon streamed that output to the Docker client, which sent it
to your terminal.

To try something more ambitious, you can run an Ubuntu container with:
$ docker run -it ubuntu bash

Share images, automate workflows, and more with a free Docker ID:
https://cloud.docker.com/

For more examples and ideas, visit:
https://docs.docker.com/engine/userguide/

查看容器状态

查看运行状态的容器

1
2
3
4

root@ubuntu:~# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
root@ubuntu:~#

查看所有状态的容器

1
2
3
4
root@ubuntu:~# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
9c6fd12bef22 hello-world "/hello" 4 minutes ago Exited (0) 4 minutes ago wizardly_mccarthy
root@ubuntu:~#

更改容器名称

1
2
3
4
5
root@ubuntu:~# docker run --name "sayHi" hello-world
root@ubuntu:~# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a74123af6f47 hello-world "/hello" 5 seconds ago Exited (0) 4 seconds ago sayHi
9c6fd12bef22 hello-world "/hello" 7 minutes ago Exited (0) 7 minutes ago wizardly_mccarthy

很多网站虽然支持 https, 但是直接在浏览器地址栏输入网址后, 默认仍是以 http 协议去访问的, http 强制跳转 https 的需求应运而生, 以下介绍三种实现的方式

rewrite 方法

这是最常用的实现方法, 将所有 http 请求通过 rewrite 重定向到 https 即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
server {  
listen 80;
server_name docs.lvrui.io

rewrite ^(.*)$ https://$host$1 permanent;
}

server {
listen 443 ssl;
server_name docs.lvrui.io;
index index.html index.htm;
access_log /var/log/nginx/docs.log main;
ssl on;
ssl_certificate /etc/ssl/docs.20150509.cn.crt;
ssl_certificate_key /etc/ssl/docs.20150509.cn.key;
error_page 404 /404.html;
location / {
root /var/www/html/docs;
}
}

497 状态码

error code 497: normal request was sent to HTTPS

在一个站点只允许 https 访问时, 如果使用 http 访问会报出497错误码

利用497状态码重定向到 https

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
server {
listen 80;
server_name docs.lvrui.io

error_page 497 https://$host$uri?$args;
}

server {
listen 443 ssl;
server_name docs.lvrui.io;
index index.html index.htm;
access_log /var/log/nginx/docs.log main;
ssl on;
ssl_certificate /etc/ssl/docs.20150509.cn.crt;
ssl_certificate_key /etc/ssl/docs.20150509.cn.key;
error_page 404 /404.html;
location / {
root /var/www/html/docs;
}
}

index.html 刷新网页

上面两种方法均会耗费服务器资源, 我们使用 curl 来看下百度是如何实现的 baidu.comwww.baidu.com 的跳转

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
$ curl baidu.com -vv 
* Rebuilt URL to: baidu.com/
* Trying 220.181.57.217...
* TCP_NODELAY set
* Connected to baidu.com (220.181.57.217) port 80 (#0)
> GET / HTTP/1.1
> Host: baidu.com
> User-Agent: curl/7.51.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Date: Sat, 01 Apr 2017 06:32:35 GMT
< Server: Apache
< Last-Modified: Tue, 12 Jan 2010 13:48:00 GMT
< ETag: "51-47cf7e6ee8400"
< Accept-Ranges: bytes
< Content-Length: 81
< Cache-Control: max-age=86400
< Expires: Sun, 02 Apr 2017 06:32:35 GMT
< Connection: Keep-Alive
< Content-Type: text/html
<
<html>
<meta http-equiv="refresh" content="0;url=http://www.baidu.com/">
</html>
* Curl_http_done: called premature == 0
* Connection #0 to host baidu.com left intact

可以看到百度很巧妙的利用meta的刷新作用,将baidu.com跳转到www.baidu.com

同理, 我们也可以用这个特性来实现 http 向 https 的跳转

1
2
3
4
# index.html
<html>
<meta http-equiv="refresh" content="0;url=https://docs.lvrui.io/">
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
server {
listen 80;
server_name docs.lvrui.io;

location / {
# 将 index.html 文件放到下面的目录下
root /var/www/html/refresh/;
}
}

server {
listen 443 ssl;
server_name docs.lvrui.io;
index index.html index.htm;
access_log /var/log/nginx/docs.log main;
ssl on;
ssl_certificate /etc/ssl/docs.20150509.cn.crt;
ssl_certificate_key /etc/ssl/docs.20150509.cn.key;
error_page 404 /404.html;
location / {
root /var/www/html/docs;
}
}

通过修改 Jenkins 的配置文件, 将登录需要密码验证的功能临时取消, 重启 Jenkins, 无密码登录后再修改对应用户的密码, 最后可以改回密码验证模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 进入 Jenkins 家目录
$ cd /var/lib/jenkins/

# 备份配置文件
$ cp config.xml config.xml.20170401

# 修改配置文件
vim config.xml

<useSecurity>true</useSecurity>
# 修改成
<useSecurity>false</useSecurity>

# 重启 Jenkins 即可无密码登录
systemctl restart jenkins

隧道技术近年来多用于实现混合云的场景, 实现云环境到自己的 IDC 机房, A 云到 B 云等需求.本篇文档主要介绍两个云之间, 使用 Linux 服务器做对接的情况.

具体原理这里不讲, 主要讲具体搭建步骤, 这里我准备了两个脚本来搭建隧道环境

configIPsec.sh

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
#!/bin/bash

# 安装软件
yum install -y openswan lsof

# 配置内核参数
echo """net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_tw_recycle = 1
net.ipv4.tcp_fin_timeout = 30

net.ipv6.conf.all.disable_ipv6 = 1
net.ipv6.conf.default.disable_ipv6 = 1
net.ipv6.conf.lo.disable_ipv6 = 1

vm.swappiness = 0
net.ipv4.neigh.default.gc_stale_time = 120
net.ipv4.conf.all.rp_filter = 0
net.ipv4.conf.default.rp_filter = 0
net.ipv4.conf.default.arp_announce = 2
net.ipv4.conf.lo.arp_announce = 2
net.ipv4.conf.all.arp_announce = 2
net.ipv4.tcp_max_tw_buckets = 5000
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_max_syn_backlog = 1024
net.ipv4.tcp_synack_retries = 2

net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.default.accept_redirects = 0
net.ipv4.conf.default.send_redirects = 0
net.ipv4.conf.eth0.accept_redirects = 0
net.ipv4.conf.eth0.send_redirects = 0
net.ipv4.conf.lo.accept_redirects = 0
net.ipv4.conf.lo.send_redirects = 0
net.ipv4.conf.default.rp_filter=0
net.ipv4.conf.eth0.rp_filter=0
#net.ipv4.conf.ip_vti0.rp_filter=0
net.ipv4.ip_forward = 1""" >> /etc/sysctl.conf

# 让配置的内核参数立即生效
sysctl -p

# 重启 ipsec 服务
systemctl restart ipsec

# 休眠2秒是为了让 udp 4500 和 500端口正常监听
sleep 2

# 检查环境是否符合要求
ipsec verify

在执行 ipsec verify 命令后, 必须保证如下回显中所有的状态均为绿色 (Hardware random device 可以为[N/A]; Opportunistic Encryption 可以为 [DISABLE]; 其他均为 ok)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
[root@99-5 ~]# ipsec verify
Verifying installed system and configuration files

Version check and ipsec on-path [OK]
Libreswan 3.15 (netkey) on 3.10.0-327.18.2.el7.x86_64
Checking for IPsec support in kernel [OK]
NETKEY: Testing XFRM related proc values
ICMP default/send_redirects [OK]
ICMP default/accept_redirects [OK]
XFRM larval drop [OK]
Pluto ipsec.conf syntax [OK]
Hardware random device [N/A]
Two or more interfaces found, checking IP forwarding [OK]
Checking rp_filter [OK]
Checking that pluto is running [OK]
Pluto listening for IKE on udp 500 [OK]
Pluto listening for IKE/NAT-T on udp 4500 [OK]
Pluto ipsec.secret syntax [OK]
Checking 'ip' command [OK]
Checking 'iptables' command [OK]
Checking 'prelink' command does not interfere with FIPSChecking for obsolete ipsec.conf options [OK]
Opportunistic Encryption [DISABLED]

保证上面的环境检查通过后, 执行如下脚本 configTunnel.sh

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
#!/bin/bash

###### 对端网络配置

# 对端公网 IP
ip_remote="59.110.174.253"

# 对端内网网段
ip_remote_vlan="192.168.20.0/24"


###### 本端网络配置

# 取公网 IP
ip_public=`curl http://members.3322.org/dyndns/getip`

# 取内网 IP
ip_private=`ifconfig | grep "inet" | grep "192.168" | awk '{print $2}'`

# 取内网 IP 的第三段作为隧道名和配置文件名字的一部分
net_vlan=`ifconfig | grep "inet" | grep "192.168" | awk '{print $2}' | awk -F "." '{print $3}'`

# 本地网段
subnet="192.168.59.0/24"

###### 秘钥
token="20150509"

###### 配置文件

# 更改 ipsec 配置文件
sed -i 's/#version 2/version 2/g' /etc/ipsec.conf
sed -i '/protostack=netkey/a\ nat_traversal=yes\n oe=off' /etc/ipsec.conf

# 创建隧道配置文件
echo """conn tunnel$net_vlan
ike=3des-sha
authby=secret
phase2=esp
phase2alg=3des-sha
compress=no
pfs=yes
type=tunnel
left=$ip_private
leftid=$ip_public
leftsubnet=$subnet
leftnexthop=%defaultroute
right=$ip_remote
rightid=$ip_remote
rightsubnet=$ip_remote_vlan
rightnexthop=%defaultroute
auto=start""" >> /etc/ipsec.d/tunnel"$net_vlan".conf

# 配置秘钥认证
echo "0.0.0.0 $ip_remote: PSK \"$token\"" >> /etc/ipsec.secrets

systemctl restart ipsec

配置完毕后, 启动该条隧道

1
ipsec auto --up tunnelName

注意: 这里的 tunnelName 是上面的脚本中根据网段序号生成的, 换成上面生成的隧道名即可


单边配置好后, 在对端以同样的方式配置并启动隧道即可


参考文档:

http://blog.leanote.com/post/251689658@qq.com/阿里云openwan与网康实现IPsec对接

虽然前面介绍了多种系统上的安装方式, 但是有一点避不开的就是伟大的长城防🔥墙, 即使是在生产环境, 从官方源安装 Docker也是一件痛苦的事情, 解决这个问题的思路无非就两种. 一种是我们自己在内网维护一套 Docker 的软件源. 另一种就是用其他人在🇨🇳搭建的 Docker 源. 本篇文件就介绍如果通过阿里的 Docker 软件源来解决国内 Docker 的安装问题

阿里镜像网站官方地址: < docker-engine >

阿里很贴心的不仅提供了国内的镜像源, 而且还提供了一键安装脚本, 该脚本在我的 Ubuntu16.04 和 Fedora 25 上通过了测试.

阿里官方提供以下系统安装 Docker 的支持

  • Ubuntu 14.04 16.04
  • Debian 7.7 8.0
  • CentOS 7
  • Fedora 20 21 22
  • Oracle Linux 6 7

安装方式:

1
curl -sSL http://acs-public-mirror.oss-cn-hangzhou.aliyuncs.com/docker-engine/internet | sh -

阿里云主机内网安装方式:

1
curl -sSL http://acs-public-mirror.oss-cn-hangzhou.aliyuncs.com/docker-engine/intranet | sh -

执行完上面的命令后即安装完成, 最后我们 看下, 上面的脚本是怎么帮我们配置 yum/dnf 源的

1
2
3
4
5
6
7
[root@191 yum.repos.d]# cat docker-main.repo 
[docker-main-repo]
name=Docker main Repository
baseurl=http://mirrors.aliyun.com/docker-engine/yum/repo/main/fedora/25
enabled=1
gpgcheck=1
gpgkey=http://mirrors.aliyun.com/docker-engine/yum/gpg

以上是我在Fedora 25上执行安装 Docker 的脚本后的软件源配置


更新

在Docker区分CE版本和EE版本之后, 阿里原有的安装镜像网站已不再提供支持, 最新的地址如下:

可以根据自己的需求安装对应的版本

熟悉 RHEL 和 CentOS 的亲一定也听说过 Fedora 发行版, 相比于”精仿版”的 CentOS, Fedora 更像是 RHEL 的近亲, 甚至是亲儿子的地位. 在 RHEL 上不支持 Docker CE 不说, 在 CentOS 上还依旧使用了 3.10+这样古老级的内核版本. 直接导致 Docker 的一些最新特性无法在该内核版本上实现. 顺理成章的 Fedora Server 版成了完美体验 Docker 的最佳”RHEL” 平台

本篇文章只介绍 Docker CE 版本在 Fedora 系统中的部署

系统需求

  • 64bit Fedora 24 Server
  • 64bit Fedora 25 Server

卸载老版本 Docker Engine

老版本的 Docker 被叫做 dockerdocker-engine 如果系统当前有这些版本的系统, 那么你需要先卸载他们

1
2
3
4
5
$ sudo dnf remove docker \
docker-common \
container-selinux \
docker-selinux \
docker-engine

需要 dnf 命令的回显显示没有相关的软件包被安装

/var/lib/docker 目录下, 包含了镜像, 容器, 数据卷网络配置

说明: 在 Fedora 中, 软件包管理器早就已经变成使用 dnf 管理了, 你仍旧可以使用 yum 命令, 但是最终还是会被重定向到 dnf. 值得欣慰的是 dnf 的用法和 yum 的用法几乎是完全一样的, 就连软件源配置文件的位置和格式也是通用的

安装 Docker

从软件源中安装 Docker

配置软件仓库 Docker-CE

  • 安装 dnf-plugins-core 工具集, 以提供 dnf config-manager命令的支持
1
$ sudo dnf -y install dnf-plugins-core
  • 配置 Docker 软件源 (Stable)
1
2
3
$ sudo dnf config-manager \
--add-repo \
https://download.docker.com/linux/fedora/docker-ce.repo
  • 开启/关闭 开发版(edge) Docker 软件源
1
2
$ sudo dnf config-manager --enable docker-ce-edge
$ sudo dnf config-manager --disable docker-ce-edge

安装 Docker CE

  • 更新软件源索引
1
$ sudo dnf makecache fast

接受 GPG key

  • 安装 Docker
1
2
$ sudo dnf install docker-ce  # 安装最新版本
$ sudo dnf -y install docker-ce-<VERSION> # 安装指定版本
  • 启动 Docker
1
2
$ sudo systemctl start docker
$ sudo systemctl enable docker
  • 验证 Docker EE 正常运行
1
$ sudo docker run hello-world
  • 升级 Docker
1
2
$ sudo dnf makecache fast
$ sudo dnf update docker-ce # sudo dnf upgrade docker-ce 两者等价

使用软件包直接安装

  • 下载对应版本的 .rpm 软件包

Docker CE: Go to https://download.docker.com/linux/fedora/7/x86_64/stable/ and download the .rpm

  • 安装软件包
1
$ sudo dnf -y install /path/to/package.rpm
  • 启动 Docker 服务
1
2
$ sudo systemctl start docker
$ sudo systemctl enable docker
  • 验证 Docker 服务正常运行
1
$ sudo docker run hello-world

卸载 Docker CE

  • 卸载 Docker CE
1
$ sudo dnf remove docker-ce
  • 镜像/容器/数据卷和自定义配置文件不会随着卸载而自动删除, 你需要手动去清除他们
1
$ sudo rm -rf /var/lib/docker

参考官方文档:

CentOS是 RHEL 的近亲, 在于对 Docker 的支持方面, CentOS 要比 RHEL 好一些, 至少, CentOS 支持 Docker CE 版本的部署. 在实际生产环境中, CentOS 服务器占有很大的比重, 但是如果需要在 CentOS 系统中使用 Docker, 比较推荐将内核升级到4.0+

本篇文章只介绍 Docker CE 版本在 CentOS 系统中的部署

系统需求

  • 64bit CentOS 7

卸载老版本 Docker Engine

老版本的 Docker 被叫做 dockerdocker-engine 如果系统当前有这些版本的系统, 那么你需要先卸载他们

1
2
3
4
5
$ sudo yum remove docker \
docker-common \
container-selinux \
docker-selinux \
docker-engine

需要 yum 命令的回显显示没有相关的软件包被安装

/var/lib/docker 目录下, 包含了镜像, 容器, 数据卷网络配置

安装 Docker

从软件源中安装 Docker

配置软件仓库 Docker-CE

  • 安装 yum-utils 工具集, 以提供 yum-config-manager命令的支持
1
$ sudo yum install -y yum-utils
  • 配置 Docker 软件源 (Stable)
1
2
3
$ sudo yum-config-manager \
--add-repo \
https://download.docker.com/linux/centos/docker-ce.repo
  • 开启/关闭 开发版(edge) Docker 软件源
1
2
$ sudo yum-config-manager --enable docker-ce-edge
$ sudo yum-config-manager --disable docker-ce-edge

安装 Docker CE

  • 更新软件源索引
1
$ sudo yum makecache fast

接受 GPG key

  • 安装 Docker
1
2
$ sudo yum install docker-ce  # 安装最新版本
$ sudo yum install docker-ce-<VERSION> # 安装指定版本
  • 启动 Docker
1
2
$ sudo systemctl start docker
$ sudo systemctl enable docker
  • 验证 Docker EE 正常运行
1
$ sudo docker run hello-world
  • 升级 Docker
1
2
$ sudo yum makecache fast
$ sudo yum update docker-ce

使用软件包直接安装

  • 下载对应版本的 .rpm 软件包

Docker CE: Go to https://download.docker.com/linux/centos/7/x86_64/stable/Packages/ and download the .rpm

  • 安装软件包
1
$ sudo yum install /path/to/package.rpm
  • 启动 Docker 服务
1
2
$ sudo systemctl start docker
$ sudo systemctl enable docker
  • 验证 Docker 服务正常运行
1
$ sudo docker run hello-world

卸载 Docker CE

  • 卸载 Docker CE
1
$ sudo yum remove docker-ce
  • 镜像/容器/数据卷和自定义配置文件不会随着卸载而自动删除, 你需要手动去清除他们
1
$ sudo rm -rf /var/lib/docker

参考官方文档:

基于时间查看 binlog 日志

1
mysqlbinlog  --no-defaults --start-datetime="2016-10-31 23:08:03" mysql-bin.000214 |more

基于位置查看 binlog 日志

1
mysqlbinlog --no-defaults --start-position=690271 mysql-bin.000214 |more