一、有了镜像才能创建容器
先拉个小的练手,centos 就够用了:
root@VM-0-9-ubuntu:~# docker pull centos
Using default tag: latest
latest: Pulling from library/centos
a1d0c7532777: Pull complete
Digest: sha256:a27fd8080b517143cbbbab9dfb7c8571c40d67d534bbdee55bd6c473f432b177
Status: Downloaded newer image for centos:latest
docker.io/library/centos:latest
root@VM-0-9-ubuntu:~# docker images
i Info → U In Use
IMAGE ID DISK USAGE CONTENT SIZE EXTRA
centos:latest a27fd8080b51 340MB 83.5MB
二、run 的参数
docker run --help 里参数一大堆,常用的就那么几个:
docker run [可选参数] image
--name="Name" # 容器名字(如 tomcat01、tomcat02),用于区分容器
-d # 后台方式运行
-it # 使用交互方式运行,进入容器查看内容,后面要跟 /bin/bash 这类 shell
-p # 指定容器的端口映射
# -p 的几种用法
-p ip:主机端口:容器端口
-p 主机端口:容器端口 # 常用格式
-p 容器端口 # 随机映射主机端口
-P # 大写 P,随机指定端口
# 启动并进入容器
root@VM-0-9-ubuntu:~# docker run -it centos /bin/bash
[root@1a67a17a9f1d /]# ll
bash: ll: command not found
# 主机名就是镜像名
[root@1a67a17a9f1d /]# ls
bin dev etc home lib lib64 lost+found media mnt opt proc root run sbin srv sys tmp usr var
# 退出容器
[root@1a67a17a9f1d /]# exit
exit
# 容器退出的快捷方式:Ctrl + D
# 两种退出方式都会停止容器运行
[root@15c41eb4491f /]# exit
root@VM-0-9-ubuntu:~# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
15c41eb4491f centos "/bin/bash" 50 seconds ago Up 49 seconds intelligent_hoover
-it 进去之后看到的就是容器里的一个小 linux,命令没几个,ll 都没有。exit 或者 Ctrl + D 退出,容器也跟着停了。
三、ps 看容器
# 正在运行的容器
root@VM-0-9-ubuntu:~# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
# -a 历史运行过的容器
root@VM-0-9-ubuntu:~# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
1a67a17a9f1d centos "/bin/bash" 3 minutes ago Exited (0) 2 minutes ago boring_leavitt
170f24ecc433 c3cbe1cc1aa5 "/hello" 2 days ago Exited (0) 2 days ago nostalgic_ptolemy
# -n=[数字] 显示最近创建的[数字]个容器,比如 -n=1,就只显示一个
# -q 只显示容器编号
# 显示运行过的所有容器的编号
root@VM-0-9-ubuntu:~# docker ps -aq
1a67a17a9f1d
170f24ecc433
容器名和容器 ID 不是一回事,都是启动容器的时候自动生成的,ps 里两个都能看到。
四、启停和删除
停止、重启、杀掉容器:
docker start|restart|stop|kill 容器id
# kill 比 stop 强制,强制停止运行
root@VM-0-9-ubuntu:~# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
f96d3ee8015f centos "/bin/bash" About a minute ago Exited (0) About a minute ago jovial_jennings
6dfe6216abfe centos "/bin/bash" About a minute ago Exited (0) About a minute ago kind_gates
a6acaefeb7a3 centos "/bin/bash" 2 minutes ago Exited (130) 2 minutes ago nervous_hermann
root@VM-0-9-ubuntu:~# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
root@VM-0-9-ubuntu:~# docker start a6acaefeb7a3
a6acaefeb7a3
root@VM-0-9-ubuntu:~# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a6acaefeb7a3 centos "/bin/bash" 3 minutes ago Up 4 seconds nervous_hermann
root@VM-0-9-ubuntu:~# docker stop a6acaefeb7a3
a6acaefeb7a3
root@VM-0-9-ubuntu:~# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
删除容器不等于删除镜像,删掉之后重新启动命令还能用,但是不挂数据卷的话里面的数据就丢了:
# 删除指定容器,运行中的删除不了,需要加参数 -f 强制删
docker rm 容器id
# 递归删除所有容器
docker rm -f `docker ps -aq`
root@VM-0-9-ubuntu:~# docker rm -f `docker ps -aq`
15c41eb4491f
1a67a17a9f1d
170f24ecc433
root@VM-0-9-ubuntu:~# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
root@VM-0-9-ubuntu:~# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
# 这样也可以
docker ps -aq | xargs docker rm -f
最后那行是另一种批量删的写法:docker ps -aq 把所有容器 ID 打出来,交给 xargs 一个个接到 docker rm -f 后面。
五、后台运行为什么会自己退
root@VM-0-9-ubuntu:~# docker run -d centos
f416c306a9d8d944fa728f3cc4c1dc2ee72fc6e4eb0e36db61fbf179167d2fdc
# 这里 8s 前启动,说明启动了就停止了
root@VM-0-9-ubuntu:~# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
f416c306a9d8 centos "/bin/bash" 9 seconds ago Exited (0) 8 seconds ago objective_khorana
f96d3ee8015f centos "/bin/bash" 5 minutes ago Exited (0) 5 minutes ago jovial_jennings
6dfe6216abfe centos "/bin/bash" 5 minutes ago Exited (0) 5 minutes ago kind_gates
a6acaefeb7a3 centos "/bin/bash" 6 minutes ago Exited (0) 2 minutes ago nervous_hermann
root@VM-0-9-ubuntu:~# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
为什么 -d 启动完自己就关了?因为后台运行必须有前台进程撑着。-it 交互式启动相当于开了个前台交互进程,所以能一直跑;光 -d 又没东西在前台跑,容器就退出了。比如装 nginx 启动后发现没提供服务,也会自己关掉。tomcat 那种主进程一直在前台跑的,就可以直接 -d。
六、看日志
用法: docker logs [选项] 容器id
获取容器的日志输出
别名:
docker container logs, docker logs
选项:
--details 显示日志提供的额外详细信息
-f, --follow 实时跟踪日志输出(类似 tail -f)
--since string 显示指定时间之后的日志(例如 "2013-01-02T13:23:37Z")或相对时间(例如 "42m" 表示 42 分钟前)
-n, --tail string 显示末尾多少行日志(默认 "all" 表示全部)
-t, --timestamps 显示时间戳
--until string 显示指定时间之前的日志(例如 "2013-01-02T13:23:37Z")或相对时间(例如 "42m" 表示 42 分钟前)
# 常用的
# 查看容器所有日志
docker logs 容器id
# 实时跟踪日志
docker logs -f 容器id
# 查看末尾 50 行
docker logs -n 50 容器id
# 查看最近 30 分钟的日志
docker logs --since 30m 容器id
# 查看带时间戳的日志
docker logs -t 容器id
短参数可以连起来写,-f -t -n 10 和 -ftn 10 是一样的:
# 跟踪查看最近带有时间戳的10条日志
docker logs -ftn 10 a6acaefeb7a3
docker logs -f -t -n 10 a6acaefeb7a3
root@VM-0-9-ubuntu:~# docker logs -ftn 10 a6acaefeb7a3
2026-07-29T08:17:06.708230213Z [root@a6acaefeb7a3 /]# ^C
2026-07-29T08:17:10.923350511Z [root@a6acaefeb7a3 /]# ^C
2026-07-29T08:17:17.196434546Z [root@a6acaefeb7a3 /]# ^C
2026-07-29T08:17:18.172594263Z [root@a6acaefeb7a3 /]# exit
2026-07-29T08:21:02.353987473Z [root@a6acaefeb7a3 /]# exit
容器里本来没东西输出,docker logs 自然是空的,那就自己写一段 shell 让它在前台一直跑:

写起来就是 docker run -d centos /bin/sh -c "while true;do echo kuangshen;sleep 1;done",注意这里的 -c 是 sh 的参数,不是 docker 的参数。有了这个前台进程,容器也就不会起来就退。
七、看进程和元数据
容器里跑着哪些进程:
root@VM-0-9-ubuntu:~# docker top a6acaefeb7a3
UID PID PPID C STIME TTY TIME CMD
root 1745326 1745301 0 16:34 pts/0 00:00:00 /bin/bash
容器的一堆底层信息用 docker inspect 看,下面只截了一部分:
docker inspect 容器id
root@VM-0-9-ubuntu:~# docker inspect a6acaefeb7a3
[
{
# 容器id只显示前几位
"Id": "a6acaefeb7a3ad7433a9cf9905a6523a8f25e71afec41c77723d2fee720fe7a1",
"Created": "2026-07-29T08:17:00.688046697Z",
"Path": "/bin/bash",
# -c 没有执行命令,为空
"Args": [],
# 状态
"State": {
"Status": "running",
"Running": true,
"Paused": false,
"Restarting": false,
"OOMKilled": false,
"Dead": false,
"Pid": 1745326,
"ExitCode": 0,
"Error": "",
"StartedAt": "2026-07-29T08:34:32.832822312Z",
"FinishedAt": "2026-07-29T08:21:02.355498409Z"
},
# 来源镜像
"Image": "sha256:a27fd8080b517143cbbbab9dfb7c8571c40d67d534bbdee55bd6c473f432b177",
"ResolvConfPath": "/var/lib/docker/containers/a6acaefeb7a3ad7433a9cf9905a6523a8f25e71afec41c77723d2fee720fe7a1/resolv.conf",
"HostnamePath": "/var/lib/docker/containers/a6acaefeb7a3ad7433a9cf9905a6523a8f25e71afec41c77723d2fee720fe7a1/hostname",
"HostsPath": "/var/lib/docker/containers/a6acaefeb7a3ad7433a9cf9905a6523a8f25e71afec41c77723d2fee720fe7a1/hosts",
"LogPath": "/var/lib/docker/containers/a6acaefeb7a3ad7433a9cf9905a6523a8f25e71afec41c77723d2fee720fe7a1/a6acaefeb7a3ad7433a9cf9905a6523a8f25e71afec41c77723d2fee720fe7a1-json.log",
"Name": "/nervous_hermann",
# 挂载
"Mounts": [],
# 基本配置
"Config": {
"Hostname": "a6acaefeb7a3",
"Domainname": "",
"User": "",
"AttachStdin": true,
"AttachStdout": true,
"AttachStderr": true,
"Tty": true,
"OpenStdin": true,
"StdinOnce": true,
# 基本环境变量
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
],
"Cmd": [
"/bin/bash"
],
"Image": "centos",
"Volumes": null,
"WorkingDir": "",
"Entrypoint": null,
"Labels": {
"org.label-schema.build-date": "20210915",
"org.label-schema.license": "GPLv2",
"org.label-schema.name": "CentOS Base Image",
"org.label-schema.schema-version": "1.0",
"org.label-schema.vendor": "CentOS"
}
},
# 网络相关
"NetworkSettings": {
"SandboxID": "a7752df2d12367daa30655e47ebb8a77e47515eb45d2e00c80d10a80371eb69d",
"SandboxKey": "/var/run/docker/netns/a7752df2d123",
"Ports": {},
"Networks": {
# 桥接
"bridge": {
"IPAMConfig": null,
"Links": null,
"Aliases": null,
"DriverOpts": null,
"GwPriority": 0,
"NetworkID": "e41e478988f569a19bdb82901caed5250272087882e92b27d822ae679ac66fb3",
"EndpointID": "f6189399d8e4f1cc7a1f8c227dcf66514c2a0e1b2a0a2639ccf5b4eb37d09201",
"Gateway": "172.17.0.1",
"IPAddress": "172.17.0.2",
"MacAddress": "92:ce:35:8f:4f:b5",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"DNSNames": null
}
}
},
"ImageManifestDescriptor": {
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"digest": "sha256:a1801b843b1bfaf77c501e7a6d3f709401a1e0c83863037fa3aab063a7fdb9dc",
"size": 529,
"platform": {
"architecture": "amd64",
"os": "linux"
}
}
}
]
想知道容器改了什么,Mounts、Config.Env、NetworkSettings 这几块最常看:挂载、环境变量、IP 都在里面。
八、进容器,exec 和 attach
容器一般都在后台跑,有时候得进去改配置。前面 run 是启动的时候就进去,现在说的是跑起来之后再进去。
# 方式1:execute 进入(译为执行)
docker exec -it id [shell]
root@VM-0-9-ubuntu:~# docker exec -it a6acaefeb7a3 /bin/bash
# 测试
[root@a6acaefeb7a3 /]# ps -ef
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 08:34 pts/0 00:00:00 /bin/bash
root 15 0 0 08:55 pts/1 00:00:00 /bin/bash
root 29 15 0 08:57 pts/1 00:00:00 ps -ef
# 方式2:attach 进入(译为附上)
docker attach id
root@VM-0-9-ubuntu:~# docker attach a6acaefeb7a3
[root@a6acaefeb7a3 /]#
# 值得一提的是,这个命令进入的是正在运行的命令行
# 如果-c执行了命令,那么就会跟踪看到输出结果
# 这种情况输出的结果会打断用户输入,所以一般使用 exec
从 ps -ef 的输出也能看出区别:exec 是新开了一个进程(PID 15)挂在容器里,attach 是直接贴到原来那个前台命令行上,别人在跑输出就会打断你的输入。所以平时用 exec。
九、容器和主机之间拷文件
docker cp 管的是容器和 linux 之间的拷贝,linux 和 windows 之间可以用 Xftp。
docker cp 容器id:容器内路径 目的主机路径
root@VM-0-9-ubuntu:~# docker attach a6acaefeb7a3
[root@a6acaefeb7a3 /]# pwd
/
[root@a6acaefeb7a3 /]# ls
bin dev etc home lib lib64 lost+found media mnt opt proc root run sbin srv sys tmp usr var
[root@a6acaefeb7a3 /]# touch test.sh
[root@a6acaefeb7a3 /]# ls
bin dev etc home lib lib64 lost+found media mnt opt proc root run sbin srv sys test.sh tmp usr var
[root@a6acaefeb7a3 /]# exit
root@VM-0-9-ubuntu:~# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
root@VM-0-9-ubuntu:~# docker cp a6acaefeb7a3:/test.sh /root
Successfully copied 0B (transferred 1.54kB) to /root
应用场景就是把容器里的数据备份到 linux 上。等后面学了数据卷,就可以做到自动同步,不用手动 cp 了。
十、常用命令小结

attach Attach to a running container # 连接到正在运行的容器
build Build an image from a Dockerfile # 通过 Dockerfile 定制镜像
commit Create a new image from a container changes # 提交当前容器为新的镜像
cp Copy files/folders from the containers filesystem to the host path # 从容器中拷贝文件或目录到宿主机
create Create a new container # 创建一个新容器(同 run,但不启动)
diff Inspect changes on a container's filesystem # 查看容器文件系统变化
events Get real time events from the server # 从 docker 服务获取容器实时事件
exec Run a command in an existing container # 在已存在的容器上运行命令
export Stream the contents of a container as a tar archive # 导出容器内容流为 tar 归档文件(对应 import)
history Show the history of an image # 展示镜像构建历史
images List images # 列出系统当前镜像
import Create a new filesystem image from the contents of a tarball # 从 tar 包内容创建新文件系统(对应 export)
info Display system-wide information # 显示系统相关信息
inspect Return low-level information on a container # 查看容器详细信息
kill Kill a running container # 终止运行中的容器
load Load an image from a tar archive # 从 tar 包加载镜像(对应 save)
login Register or Login to the docker registry server # 注册或登录 docker 服务器
logout Log out from a Docker registry server # 从 docker 服务器登出
logs Fetch the logs of a container # 输出容器日志
port Lookup the public-facing port which is NAT-ed to PRIVATE_PORT # 查看映射端口对应的容器内部端口
pause Pause all processes within a container # 暂停容器
ps List containers # 列出容器(默认只显示运行中)
pull Pull an image or a repository from the docker registry server # 从镜像仓库拉取镜像
push Push an image or a repository to the docker registry server # 推送镜像到仓库
restart Restart a running container # 重启容器
rm Remove one or more containers # 删除容器
rmi Remove one or more images # 删除镜像(需无容器使用,或加 -f 强制)
run Run a command in a new container # 创建并启动一个新容器
save Save an image to a tar archive # 保存镜像为 tar 包(对应 load)
search Search for an image on the Docker Hub # 在 Docker Hub 搜索镜像
start Start a stopped containers # 启动已停止的容器
stop Stop a running containers # 停止运行中的容器
tag Tag an image into a repository # 给镜像打标签
top Lookup the running processes of a container # 查看容器内运行的进程
unpause Unpause a paused container # 恢复暂停的容器
version Show the docker version information # 查看 docker 版本信息
wait Block until a container stops, then print its exit code # 等待容器停止并打印退出状态码
docker 的命令很多,上面这些是常用的容器和镜像命令,后面还会碰到不少。
十一、跑几个真实的服务
1. nginx
装镜像之前先去 hub 上确认版本,pull 需要的那一版:
root@VM-0-9-ubuntu:~# docker pull nginx
Using default tag: latest
latest: Pulling from library/nginx
d26f27cc8c41: Pull complete
062e450697fa: Pull complete
82454cdbf456: Pull complete
b6698f04e005: Pull complete
cacfcdd01f30: Pull complete
2bedaf25031a: Pull complete
3c7ab7949321: Pull complete
6c496f5b5050: Download complete
ea1d76ccc2c6: Download complete
Digest: sha256:5a88c9c45479443d7be2eadc894b4ed0a9801bae03d97a5760ae13b5c2005942
Status: Downloaded newer image for nginx:latest
docker.io/library/nginx:latest
root@VM-0-9-ubuntu:~# docker images
i Info → U In Use
IMAGE ID DISK USAGE CONTENT SIZE EXTRA
centos:latest a27fd8080b51 340MB 83.5MB U
nginx:latest 5a88c9c45479 241MB 66MB
启动,容器名字叫 nginx01,外部端口 3344 映射到容器里的 80:
# 容器名字指定为 nginx01,外部端口3344,内部docker为80
# 云服务器安全组需要开放3344的t/u协议
root@VM-0-9-ubuntu:~# docker run -d --name nginx01 -p 3344:80 nginx
023e8fbeaa9d1270cc3595e574944e9a9b400a94a922abf7c1a0803be0127113
root@VM-0-9-ubuntu:~# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
023e8fbeaa9d nginx "/docker-entrypoint.…" 2 seconds ago Up 2 seconds 0.0.0.0:3344->80/tcp, [::]:3344->80/tcp nginx01
本地测一下:
# 1.测试本地
root@VM-0-9-ubuntu:~# curl localhost:3344
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, nginx is successfully installed and working.
Further configuration is required for the web server, reverse proxy,
API gateway, load balancer, content cache, or other features.</p>
<p>For online documentation and support please refer to
<a href="https://nginx.org/">nginx.org</a>.<br/>
To engage with the community please visit
<a href="https://community.nginx.org/">community.nginx.org</a>.<br/>
For enterprise grade support, professional services, additional
security features and capabilities please refer to
<a href="https://f5.com/nginx">f5.com/nginx</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
# 2.运行测试
root@VM-0-9-ubuntu:~# docker images
i Info → U In Use
IMAGE ID DISK USAGE CONTENT SIZE EXTRA
centos:latest a27fd8080b51 340MB 83.5MB U
nginx:latest 5a88c9c45479 241MB 66MB U
# 3.网页测试
无问题
这里把前面说的"容器是隔离的"落实一下:容器端口是独立的,nginx01 和 nginx02 各有各的 80 端口;外部流量访问的是宿主机的端口,外网能访问到 linux,但访问不到 docker 里面,所以要用 -p 做端口映射,把宿主机和 docker 的端口打通。

映射好之后,外网访问 3344 就能测到容器里的 80 通不通:

进容器里看看 nginx 装在哪:
# 这里写容器id和名字都可以
root@VM-0-9-ubuntu:~# docker exec -it nginx01 /bin/bash
root@023e8fbeaa9d:/# whereis nginx
nginx: /usr/sbin/nginx /usr/lib/nginx /etc/nginx /usr/share/nginx
root@023e8fbeaa9d:/# cd /etc/nginx
root@023e8fbeaa9d:/etc/nginx# ls
conf.d fastcgi_params mime.types modules nginx.conf scgi_params uwsgi_params
# 停掉之后就无法访问了
root@VM-0-9-ubuntu:~# docker stop nginx01
nginx01
顺带把一个坑说清楚:exit 退出容器会让容器退出运行,是因为你退的是 shell 环境。前面用 bash 环境操作 centos,退出 shell 自然 centos 也没了;而 nginx 的主进程不是那个 bash 进程,所以你就算退出去了,nginx 照样正常跑。
2. tomcat
用 run 顺便下载,--rm 表示用完就删:
# 用run下载
docker run -it --rm tomcat
# 之前启动都是后台,停掉容器之后容器可以查到
# -it --rm 用完之后就会删除,一般用来测试用的,用完就删
root@VM-0-9-ubuntu:~# docker run -it --rm tomcat
Unable to find image 'tomcat:latest' locally
latest: Pulling from library/tomcat
4f4fb700ef54: Pull complete
ca2678b20700: Pull complete
5a66f521929b: Pull complete
93eeac639cb8: Pull complete
fe89cbdf1404: Pull complete
6f002909f8b6: Pull complete
72b04d9a8a7b: Pull complete
0fcab57e3521: Download complete
76edba644816: Download complete
root@VM-0-9-ubuntu:~# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
root@VM-0-9-ubuntu:~# docker images
i Info → U In Use
IMAGE ID DISK USAGE CONTENT SIZE EXTRA
centos:latest a27fd8080b51 340MB 83.5MB U
nginx:latest 5a88c9c45479 241MB 66MB U
tomcat:latest 3747125ecc78 601MB 160MB
root@VM-0-9-ubuntu:~# docker ps -a
# 这里没有启动tomcat
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
023e8fbeaa9d nginx "/docker-entrypoint.…" 24 minutes ago Exited (0) 5 minutes ago nginx01
f416c306a9d8 centos "/bin/bash" 4 hours ago Exited (0) 4 hours ago objective_khorana
f96d3ee8015f centos "/bin/bash" 4 hours ago Exited (0) 4 hours ago jovial_jennings
6dfe6216abfe centos "/bin/bash" 4 hours ago Exited (0) 4 hours ago kind_gates
a6acaefeb7a3 centos "/bin/bash" 4 hours ago Exited (0) 3 hours ago nervous_hermann
-it --rm 这种方式不适合在练习环境里用,一退出东西就没了。正常下载启动:
root@VM-0-9-ubuntu:~# docker pull tomcat
Using default tag: latest
latest: Pulling from library/tomcat
Digest: sha256:3747125ecc78357b5eb6e2e59352713c14a428514753fdf67db7af97999a18c4
Status: Image is up to date for tomcat:latest
docker.io/library/tomcat:latest
root@VM-0-9-ubuntu:~# docker images
i Info → U In Use
IMAGE ID DISK USAGE CONTENT SIZE EXTRA
centos:latest a27fd8080b51 340MB 83.5MB U
nginx:latest 5a88c9c45479 241MB 66MB U
tomcat:latest 3747125ecc78 601MB 160MB
root@VM-0-9-ubuntu:~# docker run -d -p 3355:8080 --name tomcat01 tomcat
769ff3c26bab5be4420ccd8a7827efef1f890e554b7e1faaf8fda2cdd7c142fe
root@VM-0-9-ubuntu:~# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
769ff3c26bab tomcat "catalina.sh run" 3 seconds ago Up 3 seconds 0.0.0.0:3355->8080/tcp, [::]:3355->8080/tcp tomcat01
安全组开放 3355 之后浏览器能访问,但是页面不对:

外网能访问说明通了,就是没显示 tomcat。进容器翻一下就明白了:
root@VM-0-9-ubuntu:~# docker exec -it tomcat01 /bin/bash
root@769ff3c26bab:/usr/local/tomcat# ls
bin CONTRIBUTING.md LICENSE NOTICE RUNNING.txt webapps
BUILDING.txt filtered-KEYS logs README.md temp webapps.dist
conf lib native-jni-lib RELEASE-NOTES upstream-KEYS work
root@769ff3c26bab:/usr/local/tomcat# ls -al
total 248
drwxr-xr-x 1 root root 4096 Jul 8 16:53 .
drwxr-xr-x 1 root root 4096 Jul 8 16:53 ..
drwxr-xr-x 2 root root 4096 Jul 8 16:54 bin
-rw-r--r-- 1 root root 26826 Jul 3 07:01 BUILDING.txt
drwxr-xr-x 1 root root 4096 Jul 29 12:36 conf
-rw-r--r-- 1 root root 8626 Jul 3 07:01 CONTRIBUTING.md
-rw-r--r-- 1 root root 30936 Jul 8 16:53 filtered-KEYS
drwxr-xr-x 2 root root 4096 Jul 8 16:53 lib
-rw-r--r-- 1 root root 60517 Jul 3 07:01 LICENSE
drwxrwxrwt 1 root root 4096 Jul 29 12:36 logs
drwxr-xr-x 2 root root 4096 Jul 8 16:54 native-jni-lib
-rw-r--r-- 1 root root 2333 Jul 3 07:01 NOTICE
-rw-r--r-- 1 root root 3224 Jul 3 07:01 README.md
-rw-r--r-- 1 root root 6470 Jul 3 07:01 RELEASE-NOTES
-rw-r--r-- 1 root root 16114 Jul 3 07:01 RUNNING.txt
drwxrwxrwt 2 root root 4096 Jul 8 16:53 temp
-rw-r--r-- 1 root root 32010 Jul 8 16:53 upstream-KEYS
drwxr-xr-x 2 root root 4096 Jul 8 16:53 webapps
drwxr-xr-x 7 root root 4096 Jul 3 07:01 webapps.dist
drwxrwxrwt 2 root root 4096 Jul 3 07:01 work
root@769ff3c26bab:/usr/local/tomcat# cd webapps
root@769ff3c26bab:/usr/local/tomcat/webapps# ls
root@769ff3c26bab:/usr/local/tomcat/webapps#
# 这里什么都没有,所以tomcat是一个阉割版显示不全很正常
# 只有最小运行环境
webapps 是空的,页面自然出不来。把 webapps.dist 里的东西拷过去就行:
root@769ff3c26bab:/usr/local/tomcat# cd webapps.dist
root@769ff3c26bab:/usr/local/tomcat/webapps.dist# ls
docs examples host-manager manager ROOT
# 两个目录互换名字也是可以的
root@769ff3c26bab:/usr/local/tomcat# cp -r webapps.dist/* webapps
root@769ff3c26bab:/usr/local/tomcat# ls webapps
docs examples host-manager manager ROOT
再访问就正常了:

以后部署项目如果每次都要进容器改文件会很麻烦,所以容器外会给一个映射路径,项目放在外面自动同步到里面,这就是 docker 的数据卷挂载,后面单独讲。
3. Elasticsearch
ELK 的架构是这样的:应用程序日志 → Filebeat(采集) → Logstash(过滤/解析) → Elasticsearch(存储/索引) → Kibana(展示)。
镜像直接去 Docker Hub 上找,官方页面右边会给一条现成的 docker pull 命令:

docker 官方给了运行方式:
# docker 官方给出了运行方式
$ docker run -d --name elasticsearch --net somenetwork -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" elasticsearch:tag
# --net 是网络配置暂时可以去掉,默认最新镜像拉不到,换了一个7.6.2
docker run -d --name elasticsearch -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" elasticsearch:7.6.2
# ES 很耗内存,可能导致交互式界面卡住
root@VM-0-9-ubuntu:~# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
5ac3a8bbfe16 elasticsearch:7.6.2 "/usr/local/bin/dock…" About a minute ago Up About a minute 0.0.0.0:9200->9200/tcp, [::]:9200->9200/tcp, 0.0.0.0:9300->9300/tcp, [::]:9300->9300/tcp elasticsearch
769ff3c26bab tomcat "catalina.sh run" 26 minutes ago Up 26 minutes 0.0.0.0:3355->8080/tcp, [::]:3355->8080/tcp tomcat01
root@VM-0-9-ubuntu:~# curl localhost:9200
{
"name" : "5ac3a8bbfe16",
"cluster_name" : "docker-cluster",
"cluster_uuid" : "r5Gd1ziVSXOF8QI5v3ioHw",
"version" : {
"number" : "7.6.2",
"build_flavor" : "default",
"build_type" : "docker",
"build_hash" : "ef48eb35cf30adf4db14086e8aabd07ef6fb113f",
"build_date" : "2020-03-26T06:34:37.794943Z",
"build_snapshot" : false,
"lucene_version" : "8.4.0",
"minimum_wire_compatibility_version" : "6.8.0",
"minimum_index_compatibility_version" : "6.0.0-beta1"
},
"tagline" : "You Know, for Search"
}
ES 太吃内存了,得限制一下。先看资源占用:
docker stats 查看CPU状态(statistics)
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
5ac3a8bbfe16 elasticsearch 0.36% 1.228GiB / 7.445GiB 16.49% 866B / 126B 0B / 1.06MB 45
769ff3c26bab tomcat01 0.05% 140.9MiB / 7.445GiB 1.85% 24.8kB / 448kB 0B / 7.76MB 37
从 docker hub 跳到 ES 的官方文档,里面写了怎么限制内存,改配置文件:
www.elastic.co/docs/release-notes/elasticsearch
# 通过参数 -e 修改配置,限制最大512M
# 可读性高的格式,容器名和端口映射需要换
docker run -d \
--name elasticsearch02 \
-p 9201:9200 \
-p 9301:9300 \
-e "discovery.type=single-node" \
-e "ES_JAVA_OPTS=-Xms64m -Xmx512m" \
elasticsearch:7.6.2
# 删掉旧的也行
# 删除未启动的冲突容器
docker rm -f elasticsearch02
# 查看内存占用 02 很明显被限制了很多
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
e9430a760e95 elasticsearch02 0.44% 339.6MiB / 7.445GiB 4.45% 656B / 126B 0B / 1.03MB 46
5ac3a8bbfe16 elasticsearch 0.10% 1.233GiB / 7.445GiB 16.56% 1.92kB / 1.11kB 0B / 1.86MB 45
769ff3c26bab tomcat01 0.12% 141.6MiB / 7.445GiB 1.86% 27.1kB / 472kB 0B / 8.09MB 37
# 测试
root@VM-0-9-ubuntu:~# curl localhost:9201
{
"name" : "e9430a760e95",
"cluster_name" : "docker-cluster",
"cluster_uuid" : "h5HEQ4XPTEafmYpFCdOHuw",
"version" : {
"number" : "7.6.2",
"build_flavor" : "default",
"build_type" : "docker",
"build_hash" : "ef48eb35cf30adf4db14086e8aabd07ef6fb113f",
"build_date" : "2020-03-26T06:34:37.794943Z",
"build_snapshot" : false,
"lucene_version" : "8.4.0",
"minimum_wire_compatibility_version" : "6.8.0",
"minimum_index_compatibility_version" : "6.0.0-beta1"
},
"tagline" : "You Know, for Search"
}
用 Kibana 连 ES 的时候要注意:容器之间互相隔离,没法直接用 localhost 连过去。linux 有内网 IP,用内网 IP 可以访问到 ES 容器和 Kibana 容器,再配合别的技术才能真正连上,这块要有点计算机网络的基础,也是 docker 的网络原理。
4. Portainer 可视化面板
Portainer 不是最佳选择,后面 CI/CD 那块最好用 rancher,但它是个现成的图形化管理工具,可以拿来先感受一下后台操作:
docker run -d -p 8088:9000 \
--restart=always \
-v /var/run/docker.sock:/var/run/docker.sock \
--privileged=true \
portainer/portainer
# --restart 先不管
# -v 是挂载,里面的数据挂载到本机
# --privileged=true 授权
docker run -d -p 8088:9000 portainer/portainer
root@VM-0-9-ubuntu:~# docker run -d -p 8088:9000 \
--restart=always \
-v /var/run/docker.sock:/var/run/docker.sock \
--privileged=true \
portainer/portainer
Unable to find image 'portainer/portainer:latest' locally
latest: Pulling from portainer/portainer
96fd13befc87: Pull complete
772227786281: Pull complete
b5d1b01b1d39: Pull complete
0bad1d247b5b: Pull complete
Digest: sha256:47b064434edf437badf7337e516e07f64477485c8ecc663ddabbe824b20c672d
Status: Downloaded newer image for portainer/portainer:latest
1f7fde25c5319446758f38cda5f0791440833f5e08cc5805fe6497be15696650
访问测试,第一次加载要连 docker、灌数据,会很慢:

设置完进去,容器情况一目了然:

容器、镜像、网络、卷这几块都能在面板里点:


以上就是 docker 的基础体系了。光有基础肯定不够用,解决不了实际需求,还得接着往下学。