容器管理

9934 字
50 分钟
容器管理

容器管理#

[TOC]


基本操作#

Terminal window
[root@Docker ~]# docker image ls | grep centos
centos:latest
# 我这里有一个Centos的镜像
1)直接运行容器
[root@Docker ~]# docker run --name v1 centos
[root@Docker ~]# docker ps
# 并没有在运行
[root@Docker ~]# docker ps -a
# 查看历史所有的容器,就可以查看到了
793de8a8f041 centos "/bin/bash" 7 seconds ago Exited (0) 7 seconds ago v1
# 它的状态是已经退出了
'因为没有被阻塞住'
# 它的命令是/bin/bash(默认运行命令)
2)sleep命令阻塞
root@Docker ~]# docker container run --name v2 centos sleep 30
# 执行完,这个终端就阻塞住了
"新开一个终端"
[root@Docker ~]# docker ps
66ea246de8d9 centos "sleep 30"
# 正在运行,命令是sleep 30
# 睡了30秒后,容器就自动退出了
[root@Docker ~]# docker ps -a -n=1
✅️显示最近创建的 1 个容器
66ea246de8d9 centos "sleep 30" Exited (0)
# 它现在就已经退出了
'回到刚才的终端'
# 命令不再阻塞
⭐结论: 这里sleep 30相当于容器的启动命令
"启动命令退出,容器就退出了"
3)tail -f命令阻塞
[root@Docker ~]# docker container run --name v3 centos tail -f /etc/hosts
# 新创建了一个容器,用tail -f阻塞住
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
...........
172.17.0.2 87c0cfd3bd45
'我们用另一个终端查看容器的状态'
[root@Docker ~]# docker container ls
87c0cfd3bd45 centos "tail -f /etc/hosts" 3 minutes ago Up 3 minutes
# 正在运行,执行命令是tail -f
# 3分钟前启动,运行了3分钟,持续阻塞ing
'启动命令不会退出--->这个容器会一直运行下去'
4)启动和停止容器的操作
docker start 容器id # 启动
docker restart 容器id # 重启
docker stop 容器id # 停止当前正在运行的容器
docker kill 容器id # 强制停止当前容器
👆简单粗暴
[root@Docker ~]# docker kill v3
# 强制停止当前容器

容器即进程#

Terminal window
'Docker 容器中进程的关系'
🥬我们先把环境清理一下!
[root@Docker ~]# docker container rm -f $(docker ps -qa)
87c0cfd3bd45
66ea246de8d9
793de8a8f041
===================================
docker ps -qa # 取出历史所有的容器id
rm -f # 强制删除容器-->后面跟容器id
docker ps -qa | xargs docker container rm -f
👆和这条命令等价
[root@Docker ~]# docker ps -a
# 现在一个也没有了
===================================
[root@Docker ~]# docker run --name v1 centos tail -f /etc/hosts
27.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
...
172.17.0.2 414f1c07ac35
# 继续让它阻塞住
'开另一终端'
[root@Docker ~]# docker container exec v1 ps -ef
# 查看容器里面的进程信息
UID PID CMD
root 1 tail -f /etc/hosts
root 6 ps -ef
===================================
docker exec:是在容器里新开一个进程
命令执行完,进程就结束
# 上面PID为6就是我们exec新开的一个进程
容器的主进程(PID 1)完全不受影响,容器继续稳稳地跑着
PID 1 的进程是容器的"主进程"
✅️这个进程是容器的生命线,它挂了容器就会退出
✅️对应着宿主机的 3637 进程
[root@Docker ~]# ps -ef | grep tail
'宿主机中查看进程信息'
root 3599 docker run --name v1 centos tail -f /etc/hosts
# 当我们执行上面docker run命令时,宿主机会创建对应的进程 3599 负责docker run操作
# 同时在容器内创建实际的 tail -f /etc/hosts 进程(PID 1)
# 这个容器内的主进程在宿主机上也有对应(PID 3637)
root 3637 tail -f /etc/hosts
===================================
[root@Docker ~]# docker container exec v1 sleep 60
'继续开一个进程进行阻塞'
[root@Docker ~]# docker container exec v1 ps -ef
# 这个ps -ef进程和上面的不是一个
# 执行完就退出-->进程即刻结束
UID PID CMD
root 1 tail -f /etc/hosts
root 19 sleep 60
root 25 ps -ef
# 除了主进程之外多了一个sleep 60
👆刚开的新进程
[root@Docker ~]# ps -ef | grep sleep
root 3761 docker container exec v1 sleep 60
# 👆对应的宿主机docker exec操作
# 同时在容器内创建实际的sleep 60进程(PID 19)
# 👇容器内sleep进程在宿主机上也有对应进程(PID 3780)
root 3780 sleep 60
===================================
[root@Docker ~]# kill 3780
# 直接杀死宿主机的sleep进程
# 容器里面对应的sleep进程(PID 19)也被杀死了
[root@Docker ~]# kill -9 3637
'必须用 -9 强制杀死才行'
# 把容器中主进程(PID 1)对应的宿主机进程杀死(PID 3637)
[root@Docker ~]# docker ps
'没有正在运行的容器'
[root@Docker ~]# docker ps -a -n=1
COMMAND STATUS
"tail -f /etc/hosts" Exited (137)
# 主进程杀死,容器直接没了(退出)
===================================
1.容器在启动的时候是有启动命令的
(1)tail -f /etc/hosts
(2)sleep 60
2.一个容器里面可以运行多个进程的
# 可以用docker exec创建多个新的进程
(1)docker run 创建容器和✅️"主进程"
(2)docker exec 在运行的容器中创建新进程
# 新的进程,并非主进程,允许挂!
3.所有容器进程 都在宿主机上有对应的真实进程
# 它俩的进程号不同
4.容器的主进程(PID 1)一旦被杀死,整个容器就会停止
# 容器中其他的进程也会挂
Note

想要让 docker ps 显示完整信息,不再出现 ...,核心秘诀就是加上 --no-trunc 参数

默认情况下,Docker 为了保持终端整洁,会把很长的命令(COMMAND 列)和容器 ID 截断显示

docker top#

  • docker top 命令查看的是宿主机(Host)视角下的进程信息

    • 类似于在宿主机执行 ps -ef | grep 命令
    • 都是为了过滤出容器内进程—>对应宿主机的==真实进程==
  • docker exec <容器名> ps -ef

    • 容器内的虚拟 PID
Terminal window
[root@Docker ~]# docker run --name v1 centos tail -f /etc/hosts
# 让它阻塞住
'新开一个终端'
[root@Docker ~]# ps -ef | grep tail
root 6978 2063 pts/1 docker run --name v1 centos tail -f /etc/hosts
root 7017 6993 ? tail -f /etc/hosts
[root@Docker ~]# docker top v1
UID PID PPID TTY CMD
root 7017 6993 ? tail -f /etc/hosts
'都能查看到这个主进程 7017'
[root@Docker ~]# docker exec v1 sleep 60
# 再新开一个进程-->阻塞住
[root@Docker ~]# docker exec v1 ps -ef
'去容器内部查看PID'
UID PID PPID TTY CMD
root 1 0 ? tail -f /etc/hosts
root 19 0 ? sleep 60
root 25 0 ? ps -ef
[root@Docker ~]# docker top v1
"查看宿主机对应的真实PID"
UID PID PPID TTY CMD
root 7017 6993 ? tail -f /etc/hosts
root 7255 6993 ? sleep 60
✅️很方便,不需要ps -ef | grep过滤了!
# 很容易就能看到某个容器对应宿主机的真实PID
特性docker top <容器名>docker exec <容器名> ps
执行位置宿主机 (由 Docker 守护进程查询)容器内部 (真正在容器里执行命令)
显示的 PID宿主机的真实 PID (如 10311)容器内的虚拟 PID (通常是 1, 15, 16…)
依赖环境不需要容器内有 ps 命令容器内必须安装了 ps (如 procps 包)
Terminal window
[root@Docker ~]# docker run --name web -d -p 81:80 nginx
209539aff72e
[root@Docker ~]# curl localhost:81
<title>Welcome to nginx!</title>
[root@Docker ~]# docker exec web ps -ef
exec failed: unable to start container process: exec: "ps":
# 这个nginx容器里面压根就没有这个命令
# 自然没有办法查看容器里面的进程
[root@Docker ~]# docker top web
'但是我们可以看宿主机对应真实的PID'
UID PID PPID TTY CMD
root 7425 7402 ? nginx: master process nginx -g daemon off;
101 7497 7425 ? nginx: worker process
# master就是主进程--->7425
[root@Docker ~]# docker ps
209539aff72e nginx "/docker-entrypoint.…"
[root@Docker ~]# kill -9 7425
[root@Docker ~]# docker ps
'杀死主进程,容器就退出了'
[root@Docker ~]# docker start web
web
[root@Docker ~]# docker ps
209539aff72e nginx "/docker-entrypoint.…"
===================================
那么如何查看容器里面的进程信息呢❓️
💡 先判断容器系统
docker exec -it web ls /bin/ | grep -E "apk|apt|yum"
# 查看容器内是否存在特定的包管理器文件
如果看到 apk -> 它是 Alpine
如果看到 apt apt-get -> 它是 Debian/Ubuntu
如果看到 yum dnf -> 它是 CentOS/RHEL/Fedora
===================================
如果是 Alpine 镜像(最常见):
docker exec -it <容器名> apk add procps
如果是 Debian/Ubuntu 镜像:
docker exec -it <容器名> apt-get install -y procps
如果是 CentOS/RHEL 镜像:
docker exec -it <容器名> yum install -y procps-ng
===================================
[root@Docker ~]# docker exec -it web ls /bin/ | grep -E "apk|apt|yum"
apt apt-get
# Debian系列的操作系统
[root@Docker ~]# docker exec -it web apt-get install -y procps
# 安装对应的包
[root@Docker ~]# docker exec web ps -ef
UID PID PPID TTY CMD
root 1 0 ? nginx: master process nginx -g daemon off;
nginx 22 1 ? nginx: worker process
root 192 0 ? ps -ef
'安装完对应的包,就能查看到容器里面的进程了!'
===================================
root@Docker:/# cat /etc/os-release
PRETTY_NAME="Debian GNU/Linux 13 (trixie)"
NAME="Debian GNU/Linux"
# Debian系列的操作系统
①先换源
cat > /etc/apt/sources.list << EOF
deb http://mirrors.ustc.edu.cn/debian/ trixie main contrib non-free
deb http://mirrors.ustc.edu.cn/debian/ trixie-updates main contrib non-free
deb http://mirrors.ustc.edu.cn/debian-security/ trixie-security main contrib non-free
EOF
②再升级软件包
root@Docker:/# apt-get update && apt-get install -y net-tools
"下下策"
find /sys/class/net -name "*"
# 查看网络接口信息
hostname -I
# 查看 IP 地址

运行容器#

当你执行 docker run --name v2 centos 时:

  • Docker 启动了一个容器并运行默认命令(如 /bin/bash
  • 但由于没有 -i(交互)和 -t(TTY伪终端)参数
    • bash 无法获得标准输入
  • bash 执行后发现没有输入流,很快就结束了
    • 容器立即退出的根本原因
  • 主进程退出 → 整个容器停止
Terminal window
1)以交互式模式运行"-it"
[root@Docker ~]# docker run -it --name v2 centos
# 直接进入到容器里面了
# @后面是容器id
[root@81d3149a35ff /]# hostname -I
172.17.0.2
[root@81d3149a35ff /]# ps -ef
UID PID PPID TTY TIME CMD
root 1 0 pts/0 00:00:00 /bin/bash
root 17 1 pts/0 00:00:00 ps -ef
# 这次就有TTY终端了--->pts/0以前都是?
[root@Docker ~]# docker exec v2 sleep 100
'在另一个终端执行睡眠命令'
[root@81d3149a35ff /]# ps -ef
UID PID PPID TTY TIME CMD
root 1 0 pts/0 00:00:00 /bin/bash
root 18 0 ? 00:00:00 sleep 100
# 这里TTY就是?
root 24 1 pts/0 00:00:00 ps -ef
[root@81d3149a35ff /]# kill -9 18
# 我们在容器里面可以进行管理-->直接杀死
[root@81d3149a35ff /]# ps -ef
UID PID PPID TTY TIME CMD
root 1 0 pts/0 00:00:00 /bin/bash
root 38 1 pts/0 00:00:00 ps -ef
# 没有sleep进程了,同时另一个终端也不阻塞了
'我们可以在容器的终端里面进行操作和管理'
2)退出容器
[root@81d3149a35ff /]# exit
exit
[root@Docker ~]# docker ps
# 没有正在运行的容器
[root@Docker ~]# docker ps -a -n=1
81d3149a35ff centos "/bin/bash" Exited (0)
# 它的状态是已退出
3)再次进入容器
[root@Docker ~]# docker start v2
v2
# 我们把v2启动起来
[root@Docker ~]# docker ps
81d3149a35ff centos "/bin/bash"
[root@Docker ~]# docker exec v2 ps -ef
# 去看一眼容器里面的进程
UID PID TTY CMD
root 1 pts/0 /bin/bash
root 15 ? ps -ef
# 这个主进程是有伪终端的
"因为我们第一次run的时候,就是-it运行的"
[root@Docker ~]# docker exec -it v2 /bin/bash
'以交互的方式再次进入到容器里面'
exec: 再次给了一个进程
✅️后面还有一个/bin/bash"启动命令"
[root@81d3149a35ff /]# ps -ef
✅️成功进入到容器里面了
UID PID PPID TTY TIME CMD
root 1 0 pts/0 00:00:00 /bin/bash
root 21 0 pts/1 00:00:00 /bin/bash
root 35 21 pts/1 00:00:00 ps -ef
# PID 21就是我们刚才exec新创建的进程
'只不过这是另一个伪终端-->pts/1'
👆和主进程的终端还不一样-->pts/0
4)断开终端连接
# 容器继续运行,进程不停止
"Ctrl+P+Q"--->小写即可
直接 exit ---> 容器停止运行,进程停止
[root@81d3149a35ff /]# read escape sequence
# 转义序列-->用来识别快捷键Ctrl+P+Q
[root@Docker ~]# docker exec v2 ps -ef
UID PID PPID TTY TIME CMD
root 1 0 pts/0 00:00:00 /bin/bash
root 21 0 pts/1 00:00:00 /bin/bash
root 36 0 ? 00:00:00 ps -ef
# 容器中这两个进程都没有停止
5)attach复用连接
-->是直接"连接"到容器的主进程(PID 1)
[root@Docker ~]# docker attach v2
'再次进入到容器中'
[root@81d3149a35ff /]# ps -ef
UID PID PPID TTY TIME CMD
root 1 0 pts/0 00:00:00 /bin/bash
root 21 0 pts/1 00:00:00 /bin/bash
root 42 1 pts/0 00:00:00 ps -ef
# 通过ps -ef命令的TTY可以知道,我们现在和主进程在同一个终端里面
[root@81d3149a35ff /]# exit
exit
"也可以用快捷键Ctrl+D进行退出"
[root@Docker ~]# docker ps
# 没有正在运行的进程
'我们刚才复用连接的是主进程'
✅️主进程退出-->整个容器直接停止
6)后台运行容器"-d"
[root@Docker ~]# docker run -d --name v3 centos
2c41e5ee85961
[root@Docker ~]# docker ps
# 没有正在运行的容器
[root@Docker ~]# docker ps -a -n=1
2c41e5ee8596 centos "/bin/bash" 28 seconds ago Exited (0) 28 seconds ago
# 28s前创建,28s前退出
"运行后立即退出"

为什么 docker run -d --name v3 centos 会退出?

  • CentOS 容器 - 默认运行 /bin/bash

根本原因:CentOS 镜像的 /bin/bash 在没有终端时立即退出

  • ✅ 设置了 -d(后台运行),但没有设置 -i-t
  • /bin/bash 启动后发现==没有标准输入/输出流==
  • ✅ bash 认为任务完成,立即退出
  • 容器主进程退出 → 整个容器停止
Terminal window
'我们再来试试nginx容器'
[root@Docker ~]# docker run -d --name web -p 81:80 nginx:latest
67c4c1e120df
'并没有设置-i和-t'-->只有-d
[root@Docker ~]# docker ps
67c4c1e120df nginx:latest "/docker-entrypoint.…" 3 seconds ago Up 2 seconds 0.0.0.0:81->80/tcp, [::]:81->80/tcp web
# 成功运行起来了
[root@Docker ~]# curl localhost:81
<title>Welcome to nginx!</title>
'也成功拉取到页面了'
===================================
docker run -d nginx # nginx 服务持续运行
docker run -d centos /bin/bash # 会导致容器立即退出
1)CentOS 容器 - 默认运行 /bin/bash
✅️ bash 是交互式程序,无终端时立即退出
2)Nginx 容器 - 默认运行 nginx 服务
✅️ nginx 是守护进程,会持续运行
Terminal window
那么,我们如何才能让Centos容器正确的放在后台运行呢❓️
-d -it
# 同时使用这些选项
"放在后台运行的同时,给输入和伪终端"
[root@Docker ~]# docker run -d -it --name v4 centos
125bfb32b3f5
[root@Docker ~]# docker ps
125bfb32b3f5 centos "/bin/bash" 3 seconds ago Up 3 seconds
# 这不就成功起来了嘛!
# 3s前启动,运行了3s
[root@Docker ~]# docker exec v4 ps -ef
UID PID PPID TTY TIME CMD
root 1 0 pts/0 00:00:00 /bin/bash
root 15 0 ? 00:00:00 ps -ef
# 我们去容器里面看一下
'主进程是有伪终端的-->pts/0'
===================================
怎么进去呢❓️
# 两种方法
(1)docker exec -it v4 /bin/bash
(2)docker attach v4
1)重新开一个进程,以交互式终端的方式进入
# 当然也新开一个伪终端
[root@Docker ~]# docker exec -it v4 /bin/bash
[root@125bfb32b3f5 /]# ps -ef
UID PID PPID TTY TIME CMD
root 1 0 pts/0 00:00:00 /bin/bash
root 21 0 pts/1 00:00:00 /bin/bash
root 35 21 pts/1 00:00:00 ps -ef
# 两个伪终端,我们在-->pts/1这里
[root@125bfb32b3f5 /]# read escape sequence
'有延迟,稍微等一下'
# Ctrl+P+Q断开连接
2)重新连接主进程的终端
root@Docker ~]# docker attach v4
[root@125bfb32b3f5 /]# ps -ef
UID PID TTY CMD
root 1 pts/0 /bin/bash
root 21 pts/1 /bin/bash
root 42 pts/0 ps -ef
# 来到了主进程的终端--->pts/0
[root@125bfb32b3f5 /]# kill -9 21
# 可以直接把pts/1伪终端的进程强制杀死
[root@125bfb32b3f5 /]# ps -ef
UID PID TTY CMD
root 1 pts/0 /bin/bash
root 44 pts/0 ps -ef
# 这样就没有pts/1了
===================================
如何删除容器❓️
docker container rm -f $(docker ps -qa)
docker ps -qa | xargs docker container rm -f
# 这两个上面已经演示过了
缺点: ❌️不管容器是否正在运行全部都删除掉了
# docker ps -qa因为它可以将所有的容器的id全部取出来
docker container prune -f
-f: ⭐不是强制删除,而是跳过确认步骤
🥬没办法删除正在运行的容器
只删除已停止的容器(Exited 状态)
它是安全的选择,不会意外删除运行中的容器
还会清理相关的缓存数据
[root@Docker ~]# docker container prune -f
Deleted Containers:
67c4c1e120dfbe5
2c41e5ee85961fc
81d3149a35ff3a8
414f1c07ac3551f
[root@Docker ~]# docker ps
125bfb32b3f5 centos "/bin/bash" 31 minutes ago Up 31 minutes
'正在运行的容器并没有受到影响'

Nginx容器详解#

Terminal window
1)正常运行
[root@Docker ~]# docker run --name web -d -p 81:80 nginx
2f5f9aad98c9
[root@Docker ~]# curl localhost:81
<title>Welcome to nginx!</title>
# 成功拉取到页面
[root@Docker ~]# docker exec web ps -ef
exec failed: unable to start container process: exec: "ps": executable file not found in $PATH
'因为容器里面压根没有 ps 这个命令'
[root@Docker ~]# docker exec -it web /bin/bash
# 因为我们run这个nginx容器的时候,并没有给伪终端
# 所以当我们要进入到nginx这个容器的时候,配合-it 和/bin/bash进入
root@2f5f9aad98c9:/# ps -ef
bash: ps: command not found
# 它是精简镜像,并且主要的目的就是跑nginx服务,所以很多命令并没有
root@2f5f9aad98c9:/# cat /etc/hosts
......
172.17.0.2 2f5f9aad98c9
root@2f5f9aad98c9:/# ls
bin dev home lib64 mnt proc run srv tmp var
boot etc lib media opt root sbin sys usr
'但它底层跑的就是Linux'
root@2f5f9aad98c9:/# cd /etc/nginx/conf.d/
root@2f5f9aad98c9:/etc/nginx/conf.d# cat default.conf
# 默认的子配置文件
server {
listen 80;
listen [::]:80;
server_name localhost;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
........
root@2f5f9aad98c9:/etc/nginx/conf.d# echo Hello World > /usr/share/nginx/html/index.html
# 修改默认主页
root@2f5f9aad98c9:/etc/nginx/conf.d# curl localhost
Hello World
'成功更改主页'
2)容器导出-->"export"
docker export 容器id > 目标名.tar.gz
-o: 也是可以的
# 作用:将指定容器的文件系统(即容器运行时的所有文件)打包成一个 tar 归档文件
root@2f5f9aad98c9:/# exit
exit
'需要在宿主机操作'
[root@Docker ~]# docker export web -o mynginx-v1.tar.gz
[root@Docker ~]# ls
mynginx-v1.tar.gz
[root@Docker ~]# scp mynginx-v1.tar.gz 10.0.0.128:~
mynginx-v1.tar.gz 100% 155MB 142.8MB/s
# 传输给另一台机器
3)容器导入"import"
docker import -m "描述信息" 压缩包 <新镜像名>:<tag>
[root@test ~]# docker import -m "从容器导入" mynginx-v1.tar.gz myweb:1.0
[root@test ~]# docker images
myweb 1.0 58456a1acc71
[root@test ~]# docker run --name web -d -p 82:80 myweb:1.0
docker: Error response from daemon: no command specified.
# 没有特殊的启动命令
[root@test ~]# docker run --name web -d -p 82:80 myweb:1.0 /bin/bash
# 那我们就给一个启动命令 /bin/bash
2656467d8
[root@test ~]# docker ps
# 但是容器并没有启动起来
启动完即刻退出
'/bin/bash 需要有标准的输入输出才行'
[root@test ~]# docker run --name web-test -d -it -p 82:80 myweb:1.0 /bin/bash
2f554a82dbdf
[root@test ~]# docker attach web-test
root@2f554a82dbdf:/# curl localhost
curl: (7) Failed to connect to localhost port 80 after 0 ms: Could not connect to server
# 没有办法拉取到页面
这是为什么呢???

文件系统 vs 元数据#

关键点docker export 导出的只是容器的文件系统快照,它不包含原始镜像的元数据,例如:

  • 镜像的历史构建层
  • 环境变量 (ENV)
  • 端口暴露 (EXPOSE)
  • 默认启动命令 (CMD) 等配置

image-20260418171836427
image-20260418171836427

🧅 镜像的“千层饼”结构

你可以把一个 Docker 镜像想象成一个由很多层“千层饼”叠加起来的东西

  • 每一层 (Layer)docker history 里的每一行,就代表一层“饼”
  • 最下面一层:这是基础层,就像饼的“饼底”
    • # debian.sh ... 这一层,它构建了一个基础的 Debian 操作系统
  • 中间和上面的层:在“饼底”之上,又一层层地叠加了新的东西
    • 比如 RUN ... 那一层,是在 Debian 的基础上安装了 Nginx 软件,所以它的大小是 85.4MB
    • 再上面的 COPY ... 层,是拷贝了一些脚本文件

所以,整个镜像的文件系统,是由所有这些层从下到上叠加、合并后最终呈现的样子


🏷️ 元数据:每一层的“说明书”

到底哪些是元数据呢?答案是:

docker history 命令展示的每一行信息,本身就是元数据

描述每一层“是什么”和“怎么做”的信息

  • CMD ["nginx" "-g" "daemon off;"]:这是一条元数据,它告诉 Docker:“用这个镜像启动容器时,默认执行这个命令”
  • EXPOSE map[80/tcp:{}]:这也是一条元数据,它声明:“这个容器建议暴露 80 端口”
  • ENV NGINX_VERSION=1.29.8:这还是元数据,它定义了一个环境变量
  • RUN /bin/sh -c ...:这同样是元数据,它记录了“这一层是通过运行这个 shell 命令构建出来的”

✅️你可以看到,有些元数据(如 CMD, ENV)只描述配置,所以 SIZE0B

✅️而像 RUN 这样的元数据,因为它执行了安装软件的操作,所以它关联的层就有 85.4MB 的大小


图片变清晰
图片变清晰

  • 上面镜像层中的文件 ==app2.0== 覆盖了下层 ==app1.0==
    • 相当于做了版本升级
    • 如果所需要的某一层已经存在了,就不需要下载了

docker export 做的事情非常“粗暴”:

  1. 它会把所有层(千层饼)压扁、合并成一个整体
    1. 它不管你原来有多少层,也不管每一层是怎么来的
  2. 它只拿走合并后的最终文件系统
    1. 也就是把所有层叠加后,容器里能看到的==所有文件和目录==
    2. 这就是为什么导出的 tar 包大小和容器实际占用的磁盘空间差不多
  3. 它把所有“说明书”(元数据)全部扔掉
    1. CMDENVEXPOSELABEL 以及每一层的构建历史,统统不包含在 tar 包里

所以,docker export 导出的文件,就像一个没有说明书、被压成一块的饼干

它的“内容物”(文件)都在,所以体积没变

但你已经不知道它原来是怎么做的,也不知道该怎么“启动”它了

对比项docker history / 原始镜像docker export 导出的 tar 包
结构多层叠加的“千层饼”压扁合并的“一张饼”
文件系统由所有层叠加而成只包含最终合并后的文件
元数据完整保留 (CMD, ENV, 构建历史等)全部丢失
包含内容文件 + 所有“说明书”只有文件

📥 import 导入为镜像

作用:将 tar 文件的内容作为一个新的文件系统层,并创建一个新的 Docker 镜像

  • docker import -m “描述信息” 压缩包 <新镜像名>:

关键点

  • docker import 会创建一个全新的、扁平化的镜像,不包含任何历史层
  • -m 参数可以为这次导入操作添加一条提交信息,方便记录
  • 由于原始元数据已丢失,这个新镜像没有默认的启动命令
    • 需要在运行它时手动指定要执行的命令
特性docker export / docker importdocker save / docker load
操作对象容器 (Container)==镜像 (Image)==
保留元数据否,只保留文件系统是,保留所有层、标签和历史
适用场景快速迁移容器状态,创建轻量级==基础镜像==完整备份或迁移镜像,保留所有信息
Terminal window
[root@test ~]# docker import -m "从容器导入" mynginx-v1.tar.gz myweb:1.0
sha256:5fced15845fb
[root@test ~]# docker images
myweb 1.0 5fced15845fb
[root@test ~]# docker history myweb:1.0
IMAGE CREATED BY SIZE COMMENT
5fced15845fb 159MB 从容器导入
"扁平化的镜像,不包含任何历史层"
[root@test ~]# docker run -d -p 81:80 --name test myweb:1.0
docker: Error response from daemon: no command specified.
'没有启动命令自然也不知道如何启动'
[root@test ~]# docker run -d -p 81:80 --name test myweb:1.0 nginx -g 'daemon off;'
===================================
'启动命令'
正常模式(daemon on)
- Nginx 启动后会 fork(创建) 子进程,主进程退出到后台
- 不适合 Docker 容器(容器会认为主进程结束)
- 主进程结束,容器退出
daemon off 模式:
Nginx 进程保持前台运行
主进程持续运行,保持容器存活
Docker 容器不会立即退出
===================================
[root@test ~]# docker ps
4a2e407c08ab myweb:1.0 "nginx -g 'daemon of…"'
[root@test ~]# curl localhost:81
Hello World
'把它删除了'
[root@test ~]# docker rm -f $(docker ps -aq)
4a2e407c08ab
[root@test ~]# docker rmi myweb:1.0
# 镜像也删除了
'重新导入一遍'
[root@test ~]# docker import -m "从容器导入" -c 'CMD ["nginx", "-g", "daemon off;"]' mynginx-v1.tar.gz myweb:1.0
sha256:588b2bbdb508
-c: 指定 CMD (启动命令)
[root@test ~]# docker run -d -p 81:80 --name test myweb:1.0
# 并没有指定启动命令
[root@test ~]# curl localhost:81
Hello World
'成功拉取到了'
[root@test ~]# docker history myweb:1.0
IMAGE CREATED BY SIZE COMMENT
588b2bbdb508 159MB 从容器导入
# 并没有启动命令
在export导出的时候,就被压成一层
===================================
`docker history` 主要展示的是“镜像层”的构建历史,而不是“镜像配置”的内容
-c 参数--->写入了这个新镜像的配置 (Config) 中
[root@test ~]# docker inspect myweb:1.0
"Cmd": [
"nginx",
"-g",
"daemon off;"
# 在这里面可以看到!

元数据对比#

Terminal window
'通过查看inspect详细信息对比元数据'
-f 参数
# 只看你关心的字段
[root@Docker ~]# docker inspect -f '{{.Config.Cmd}}' nginx:latest
[nginx -g daemon off;]
[root@Docker ~]# docker inspect -f '{{.Config.Env}}' nginx:latest
[PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin NGINX_VERSION=1.29.8 NJS_VERSION=0.9.6 NJS_RELEASE=1~trixie ACME_VERSION=0.3.1 PKG_RELEASE=1~trixie DYNPKG_RELEASE=1~trixie]
[root@Docker ~]# docker inspect -f '{{.Os}}' nginx:latest
linux
===================================
export 导出前的nginx镜像
[root@Docker ~]# docker inspect nginx:latest
............
"Comment": "buildkit.dockerfile.v0",
"Created": "2026-04-07T17:31:28.277378375Z",
"Config": {
"ExposedPorts": {
"80/tcp": {}
},
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
"NGINX_VERSION=1.29.8",
"NJS_VERSION=0.9.6",
"NJS_RELEASE=1~trixie",
"ACME_VERSION=0.3.1",
"PKG_RELEASE=1~trixie",
"DYNPKG_RELEASE=1~trixie"
],
"Entrypoint": [
"/docker-entrypoint.sh"
],
"Cmd": [
"nginx",
"-g",
"daemon off;"
],
"Labels": {
"maintainer": "NGINX Docker Maintainers <docker-maint@nginx.com>"
},
"StopSignal": "SIGQUIT"
},
"Architecture": "amd64",
"Os": "linux",
"Size": 62960006,
"RootFS": {
"Type": "layers",
"Layers": [
"sha256:60e70dddd9ea3b1c77c62fe78be1d9f485706b6fe6052c3d88612bd8f56acd67",
"sha256:a4b536aa4bf889a8c0312f8d973adca585cdf71dbd7b57112fa16364b1bf8824",
"sha256:4ef7ac306afb6bfe451d606d7c24e63cdaa41e7a6be29f6d5153e6df2a567919",
"sha256:3fd3ceafa06466d84786fabaf781e36d0292034ae6b86c782df176c4da98584f",
"sha256:db010d6b6a3c1a9a8e6a28a188a91c2cf6904bdf466bbdb512cb112aa30dc2b4",
"sha256:5ca2f881e5bf8044202501c4a0e208a00f16d0a015197216740bdfe911f9ce31",
"sha256:9d09dfdcffeb4bc4651caa6f7f8d40a0ba72e0ef5215a67cee4fffed173f53f7"
]
...........
===================================
导出为tar包后,再 import 导入
[root@test ~]# docker inspect myweb:1.0
"Comment": "从容器导入",
"Created": "2026-04-18T09:58:49.347464746Z",
"DockerVersion": "26.1.4",
"Author": "",
"Config": {
❌️配置这块基本就是空白的!
"Hostname": "",
"Domainname": "",
"User": "",
"AttachStdin": false,
"AttachStdout": false,
"AttachStderr": false,
"Tty": false,
"OpenStdin": false,
"StdinOnce": false,
"Env": null,
"Cmd": [
"nginx",
"-g",
"daemon off;"
],
✅️ Cmd这块是我import -c加入进去的配置
"Image": "",
"Volumes": null,
"WorkingDir": "",
"Entrypoint": null,
"OnBuild": null,
"Labels": null
},
"Architecture": "amd64",
"Os": "linux",
"Size": 159251302,
"RootFS": {
"Type": "layers",
"Layers": [
"sha256:bc40f419f5834c682a0b00e3432b0e9b0eaa491732e20bb8c9174393609b21b8"
]

docker commit#

  • 保留元数据:保留容器的所有元数据
    • 环境变量、CMD、暴露端口等
  • 保持分层:不会破坏原有的分层结构
    • 在基础镜像的各层之上增加一个新的改动层
  • 输出镜像:直接生成一个==新的镜像==
    • 保存在==本地== ---> 配合docker save/load 进行==迁移==
      • 👇下面俩操作对象是==容器==----👆操作对象为==镜像==
特性docker commitdocker export/import
元数据保留✅ 保留❌ 丢失
分层结构✅ 保持分层❌ 扁平化
文件系统包含所有变更仅文件系统快照
历史记录保留基础镜像历史丢弃所有历史记录
适用场景==保存容器状态====制作基础镜像==
Terminal window
[root@Docker ~]# docker run -d --name web -p 81:80 nginx
8b7de7077
[root@Docker ~]# docker exec -it web /bin/bash
root@8b7de7077c07:/# curl localhost
<title>Welcome to nginx!</title>
root@8b7de7077c07:/# echo Hello World > /usr/share/nginx/html/index.html
root@8b7de7077c07:/# curl localhost
Hello World
[root@Docker ~]# docker commit web my-web:1.0
sha256:2668ca268ea5
[root@Docker ~]# docker images
nginx:latest 7f0adca1fc6c
my-web:1.0 2668ca268ea5
👆是我们刚提交的镜像,"两个镜像id都不同"
[root@Docker ~]# docker history nginx:latest
7f0adca1fc6c 12 days ago CMD ["nginx" "-g" "daemon off;"]
<missing> 12 days ago STOPSIGNAL SIGQUIT
<missing> 12 days ago EXPOSE map[80/tcp:{}]
<missing> 12 days ago ENTRYPOINT ["/docker-entrypoint.sh"]
[root@Docker ~]# docker history my-web:1.0
2668ca268ea5 2 minutes ago nginx -g daemon off;
7f0adca1fc6c 12 days ago CMD ["nginx" "-g" "daemon off;"]
<missing> 12 days ago STOPSIGNAL SIGQUIT
<missing> 12 days ago EXPOSE map[80/tcp:{}]
<missing> 12 days ago ENTRYPOINT ["/docker-entrypoint.sh"]
'添加了一个新的改动层!'
✅️元数据和分层结构都保留着呢!
[root@Docker ~]# docker save my-web:1.0 > webserver-v1.0.tar.gz
# 导出为tar包
[root@Docker ~]# scp webserver-v1.0.tar.gz 10.0.0.128:~
# 迁移至另一个虚拟机
[root@test ~]# ll
'另一台机器'
-rw-r--r-- 1 root root 62963712 4月 20 08:47 webserver-v1.0.tar.gz
[root@test ~]# docker load < webserver-v1.0.tar.gz
[root@test ~]# docker images
my-web 1.0 a439601f00e2
[root@test ~]# docker history my-web:1.0
a439601f00e2 2 minutes ago nginx -g daemon off;
<missing> 12 days ago CMD ["nginx" "-g" "daemon off;"]
<missing> 12 days ago STOPSIGNAL SIGQUIT
<missing> 12 days ago EXPOSE map[80/tcp:{}]
<missing> 12 days ago ENTRYPOINT ["/docker-entrypoint.sh"]
✅️'和导出前的分层结构和元数据保持一致'
[root@test ~]# docker run -d --name web -p 81:80 my-web:1.0
[root@test ~]# curl localhost:81
Hello World

cp拷贝命令#

docker cp 的核心作用就是打破容器与宿主机之间的隔离,实现文件的双向复制

  • 这个命令是在宿主机的终端中执行的,不需要进入容器内部
    • 拷贝是一个手动的过程,未来我们使用 -v 容器卷的技术,可以实现自动同步
传输方向命令格式
宿主机 → 容器docker cp <宿主机路径> <容器ID/名称>:<容器内路径>
容器 → 宿主机docker cp <容器ID/名称>:<容器内路径> <宿主机路径>
Terminal window
[root@Docker ~]# echo kpyun > test.md
[root@Docker ~]# ls
test.md
[root@Docker ~]# pwd
/root
[root@Docker ~]# docker run -it --name v1 centos:latest
[root@af1f7ec76b82 /]# cd /home
[root@af1f7ec76b82 home]# ls
[root@af1f7ec76b82 home]# pwd
/home
[root@af1f7ec76b82 home]# echo Docker > v1.md
# 创建测试文件
[root@af1f7ec76b82 home]# ✅️Ctl+P+Q断开终端连接
[root@Docker ~]# docker cp /root/test.md v1:/home
Successfully copied 6B (transferred 2.05kB) to v1:/home
# 把本地的测试文件拷贝至容器中
[root@Docker ~]# docker cp v1:/home/v1.md /root
Successfully copied 7B (transferred 2.05kB) to /root
# 把容器中的文件,拷贝至宿主机中
[root@Docker ~]# cat /root/v1.md
✅️Docker
[root@Docker ~]# docker attach v1
# 进入到容器中
[root@af1f7ec76b82 home]# cat test.md
✅️kpyun
[root@af1f7ec76b82 home]# exit
exit

传入环境变量#

Terminal window
-e "传递环境变量"
[root@Docker ~]# docker run -d -it -e SCHOOL=oldboy --name v1 centos
[root@Docker ~]# docker exec v1 env
PATH=/usr/local/sbin:/usr/local/bin...
HOSTNAME=82f06844dfc9
SCHOOL=oldboy
👆就是我们传递的环境变量
HOME=/root
[root@Docker ~]# docker attach v1
'进入到容器里面'
[root@82f06844dfc9 /]# env | grep SCHOOL
SCHOOL=oldboy
# 同样可以过滤出来

日志信息#

Terminal window
docker logs --> "查看日志信息"
-f: # 实时跟踪日志输出
-n=num: # 只显示最后 num 行日志
-t: # 显示时间戳
--since: # 显示自某时刻之后的日志
👆面试题,最近20分钟的日志 --> 20m
[root@Docker ~]# docker run -d --name web -p 81:80 nginx
480a3d495bee
[root@Docker ~]# docker ps -l
480a3d495bee nginx "/docker-entrypoint.…"
[root@Docker ~]# curl localhost:81
<title>Welcome to nginx!</title>
'开另一个终端'
[root@Docker ~]# docker logs -t -n=1 web
# 最后一行日志
2026-04-18T14:05:59.567636346Z 172.17.0.1 - - [18/Apr/2026:14:05:59 +0000] "GET / HTTP/1.1" 200 896 "-" "curl/8.12.1" "-"
# 运行完即刻退出
[root@Docker ~]# docker logs -tf web
'实时追踪日志'
[root@Docker ~]# docker logs -t --since 20m web
# 最近20分钟的日志信息
'加上-f实时显示'

重启策略#

重启策略直接重启
Docker服务
先手动stop
(Exited 137)
再重启Docker服务
异常退出正常退出正常退出后
(Exited 0)
再stop停止
(Exited非0)
再重启Docker服务
no(默认策略)不启动 🛑不启动 🛑不重启 🛑不重启 🛑不启动 🛑
正常退出后
==always==✅️启动 🟢启动 🟢重启 🔄重启 🔄启动 🟢
正常退出后
==unless-stopped==✅️启动 🟢不启动 🔴重启 🔄重启 🔄不启动 🔴
正常退出后
on-failure启动 🟢启动 🟢重启 🔄
(可以限制次数:3)
不重启 🛑不启动 🔴
正常退出后
Terminal window
--restart 重启策略
===============================
always # 一直重启
unless-stopped # 只有手动stop了,才不启动
on-failure # 失败了重启,正常退出不重启

==异常退出(Exited 非0):==(如 Exited 137)

  • 容器挂了(进程崩溃)
    • 比如程序报错、内存溢出、或者被 kill -9 干掉
Important

注意:手动执行 docker stop,它的状态码也是 Exited 137

  • 但它不算异常退出

  • 在 Docker 眼里算作“正常休假”,所有策略都不会自动重启它

  • ==正常退出(Exited 0)== 启动命令退出(如 sleep 10 结束)

  • ==重启Docker服务== ---> 执行 systemctl restart docker

    • 模拟服务器断电
Terminal window
1)环境清理
[root@Docker ~]# docker rm -f $(docker ps -aq)
2)拉取镜像
[root@Docker ~]# docker pull docker.xuanyuan.run/alpine:3.20.2
[root@Docker ~]# docker images
alpine:3.20.2 0a4eaa0eecf5
"Alpine Linux 是容器化时代的“轻量级王者”"
# 镜像体积上 Alpine 只有 CentOS 的 1/40
3)运行容器
[root@Docker ~]# docker container run -d -it --name c1-no --restart no alpine:3.20.2
# 默认重启策略
[root@Docker ~]# docker container run -d -it --name c2-always --restart always alpine:3.20.2
# 始终重启
[root@Docker ~]# docker container run -d -it --name c3-unless-stopped --restart unless-stopped alpine:3.20.2
[root@Docker ~]# docker container run -d -it --name c4-on-failure --restart on-failure alpine:3.20.2
[root@Docker ~]# docker container run -d -it --name c5-on-failure-max --restart on-failure:3 alpine:3.20.2
'和上一个重启策略一样'
# 指定了最大重启次数-->3
[root@Docker ~]# docker ps
CONTAINER ID IMAGE STATUS NAMES
c0a126fc0013 alpine:3.20.2 Up 4 minutes c5-on-failure-max
43cdba8d6738 alpine:3.20.2 Up 4 minutes c4-on-failure
ce514fe3dd72 alpine:3.20.2 Up 4 minutes c3-unless-stopped
5db38a13c1cc alpine:3.20.2 Up 4 minutes c2-always
d8e1ad8954d0 alpine:3.20.2 Up 5 minutes c1-no
===============================
🌰直接restart重启容器
[root@Docker ~]# systemctl restart docker
[root@Docker ~]# docker ps -a
CONTAINER ID IMAGE STATUS NAMES
c0a126fc0013 alpine:3.20.2 Up 9 seconds c5-on-failure-max
43cdba8d6738 alpine:3.20.2 Up 9 seconds c4-on-failure
ce514fe3dd72 alpine:3.20.2 Up 9 seconds c3-unless-stopped
5db38a13c1cc alpine:3.20.2 Up 9 seconds c2-always
d8e1ad8954d0 alpine:3.20.2 Exited (137) c1-no
# Exited (0) 正常执行完命令退出
===============================
🌰先停止容器,再重启服务
[root@Docker ~]# docker stop $(docker ps -qa)
'正常停止挺慢的,需要等10s'
-t 0
✅️ 立即重启
[root@Docker ~]# docker start $(docker ps -qa)
[root@Docker ~]# docker stop -t 0 $(docker ps -qa)
'你会发现速度明显上来了'
[root@Docker ~]# docker ps -a
STATUS
Exited (137)
Exited (137)
Exited (137)
Exited (137)
Exited (137)
stop的状态码Exited (137) "非0"
'stop后--->都停止运行了'
✅️手动stop停止,都不重启
✅️stop-->非异常退出
[root@Docker ~]# systemctl restart docker
[root@Docker ~]# docker ps -a
CONTAINER ID IMAGE STATUS NAMES
c0a126fc0013 alpine:3.20.2 Up 9 seconds c5-on-failure-max
43cdba8d6738 alpine:3.20.2 Up 9 seconds c4-on-failure
ce514fe3dd72 alpine:3.20.2 Exited (137) c3-unless-stopped
5db38a13c1cc alpine:3.20.2 Up 9 seconds c2-always
d8e1ad8954d0 alpine:3.20.2 Exited (137) c1-no
===============================
🌰都启动起来后,kill -9杀死
# 模仿异常退出
[root@Docker ~]# docker start `docker ps -qa`
# 这里是反引号效果等同$()
"先全部启动起来"
[root@Docker ~]# docker top c1-no
'看c1-no中宿主机对应的PID'
UID PID PPID TTY TIME CMD
root 4689 4662 pts/0 00:00:00 /bin/sh
# 只有一个,4689就是它的主进程对应的PID
[root@Docker ~]# docker inspect -f "{{.State.Pid}}" c1-no
4689
'当然我们也可以用inspect去查看'
✅️.State.Pid 的含义:
🌿这个字段特指容器启动时运行的第一个进程
🌿也就是 PID 1 的主进程-->在宿主机上对应的 进程ID
[root@Docker ~]# docker inspect -f "{{.State.Pid}}" `docker ps -aq`
4472
4487
4625
4464
4689
# 把所有容器的主进程取出来
[root@Docker ~]# docker container inspect -f {{.State.Pid}} `docker ps -aq` | xargs kill -9
'都强制杀死'
[root@Docker ~]# docker ps -a
c0a126fc0013 alpine:3.20.2 Up 9 seconds c5-on-failure-max
43cdba8d6738 alpine:3.20.2 Up 9 seconds c4-on-failure
ce514fe3dd72 alpine:3.20.2 Up 9 seconds c3-unless-stopped
5db38a13c1cc alpine:3.20.2 Up 9 seconds c2-always
d8e1ad8954d0 alpine:3.20.2 Exited (137) c1-no
[root@Docker ~]# docker container inspect -f {{.State.Pid}} `docker ps -aq` | xargs kill -9
'在执行第4次后强制杀死之后'
✅️c5-on-failure-max挂了,因为已经达到最大的重启次数了
[root@Docker ~]# docker ps -a
c0a126fc0013 alpine:3.20.2 Exited (137) c5-on-failure-max
43cdba8d6738 alpine:3.20.2 Up 9 seconds c4-on-failure
ce514fe3dd72 alpine:3.20.2 Up 9 seconds c3-unless-stopped
5db38a13c1cc alpine:3.20.2 Up 9 seconds c2-always
d8e1ad8954d0 alpine:3.20.2 Exited (137) c1-no
===============================
🌰正常退出
✅️启动时指定容器的启动命令 sleep 10
✅️执行完命令后正常退出Exited (0)
[root@Docker ~]# docker rm -f `docker ps -qa`
"先清理环境"
docker run -d -it --name c1-no --restart no alpine:3.20.2 sleep 10
docker run -d -it --name c2-always --restart always alpine:3.20.2 sleep 10
docker run -d -it --name c3-unless-stopped --restart unless-stopped alpine:3.20.2 sleep 10
docker run -d -it --name c4-on-failure --restart on-failure alpine:3.20.2 sleep 10
docker run -d -it --name c5-on-failure-max --restart on-failure:3 alpine:3.20.2 sleep 10
[root@Docker ~]# docker ps
CONTAINER ID COMMAND STATUS NAMES
e140e3afe0f6 "sleep 10" Up 2 seconds c5-on-failure-max
0740e7cb35a7 "sleep 10" Up 3 seconds c4-on-failure
06e01a832866 "sleep 10" Up 3 seconds c3-unless-stopped
5a010d061926 "sleep 10" Up 3 seconds c2-always
a1d86c69344d "sleep 10" Up 3 seconds c1-no
'等10s再次查看'
[root@Docker ~]# docker ps -a
CONTAINER ID COMMAND STATUS NAMES
e140e3afe0f6 "sleep 10" Exited (0) c5-on-failure-max
0740e7cb35a7 "sleep 10" Exited (0) c4-on-failure
06e01a832866 "sleep 10" Up 9 seconds c3-unless-stopped
5a010d061926 "sleep 10" Up 9 seconds c2-always
a1d86c69344d "sleep 10" Exited (0) c1-no
===============================
🌰正常退出后,再手动stop,在重启服务
[root@Docker ~]# docker stop -t 0 $(docker ps -aq)
[root@Docker ~]# docker ps -a
CONTAINER ID COMMAND STATUS NAMES
e140e3afe0f6 "sleep 10" Exited (0) c5-on-failure-max
0740e7cb35a7 "sleep 10" Exited (0) c4-on-failure
06e01a832866 "sleep 10" Exited (137) c3-unless-stopped
5a010d061926 "sleep 10" Exited (137) c2-always
a1d86c69344d "sleep 10" Exited (0) c1-no
'后面是为了比较always和unless-stopped'
⚠️on-failure在正常退出后,就不会启动了
[root@Docker ~]# systemctl restart docker
[root@Docker ~]# docker ps -a
CONTAINER ID COMMAND STATUS NAMES
e140e3afe0f6 "sleep 10" Exited (0) c5-on-failure-max
0740e7cb35a7 "sleep 10" Exited (0) c4-on-failure
06e01a832866 "sleep 10" Exited (137) c3-unless-stopped
5a010d061926 "sleep 10" Up 5 seconds c2-always
a1d86c69344d "sleep 10" Exited (0) c1-no
✅️always坚挺到了最后

四种状态#

状态关键词含义能否提供服务备注
Created已创建容器实例已生成,配置(端口、挂载)已就绪,但主进程未启动❌ 不能适合预配置、等待触发启动
Up (Running)运行中容器主进程正在运行,资源正常消耗✅ 能这是正常工作的状态
Exited (Dead)已退出主进程已停止(可能是任务完成,也可能是报错崩溃)❌ 不能退出码 0 代表正常退出(如执行完脚本);
0 代表异常
Paused暂停进程被“冻结”在内存中,不消耗 CPU❌ 不能类似VMware的==挂起==
资源在内存中而非磁盘

docker create 是在“写配置文件”,而 docker run 是“直接开机”

  • 什么时候用 docker run
    • 90% 的场景
    • 当你想要“一键启动”服务时,直接用 run
    • 它本质上是 create + start 的合体
  • 什么时候用 docker create
    • 当你需要**“先占坑,后启动”**时
参数docker create 中 (仅创建)
-p (端口映射)记录配置
容器处于 Created 状态时端口未开启
外部无法访问
-d (后台运行)==无意义/被忽略==
容器根本没启动,无所谓前台还是后台
-it (交互终端)记录配置
容器未启动,没有终端
-v (挂载卷)记录配置
准备好挂载点,等待启动
—name (名称)给容器命名(方便后续 start)
Terminal window
[root@Docker ~]# docker create --name v1 -it alpine:3.20.2
[root@Docker ~]# docker ps -a
c6ebb753e991 alpine:3.20.2 "/bin/sh" Created
[root@Docker ~]# docker start v1
[root@Docker ~]# docker ps
c6ebb753e991 alpine:3.20.2 "/bin/sh" Up 5 seconds
"由Created --> Up"
[root@Docker ~]# docker pause v1
[root@Docker ~]# docker ps
c6ebb753e991 alpine:3.20.2 "/bin/sh" Up 5 seconds (Paused)
✅️后面多了个Paused
[root@Docker ~]# docker exec -it v1 /bin/bash
# 尝试进入
Container v1 is paused, unpause the container before exec
# 被暂停,exec之前先unpause
[root@Docker ~]# docker unpause v1
'取消暂停'
[root@Docker ~]# docker ps
c6ebb753e991 alpine:3.20.2 "/bin/sh" Up 5 seconds
[root@Docker ~]# docker exec -it v1 /bin/bash
exec: "/bin/bash": stat /bin/bash: no such file or directory
'因为alpine它是最简镜像,没有/bin/bash'
✅️用sh
[root@Docker ~]# docker exec -it v1 sh
/ # whoami
root
/ # exit

项目部署案例#

部署mysql服务#

Terminal window
[root@Docker ~]# docker pull docker.xuanyuan.run/mysql:8.0.36
[root@Docker ~]# docker images
docker.xuanyuan.run/mysql:8.0.36 a53272402242
[root@Docker ~]# docker tag docker.xuanyuan.run/mysql:8.0.36 mysql:8.0.36
# 我们给打个标签
[root@Docker ~]# docker images
mysql:8.0.36 a53272402242
[root@Docker ~]# docker run -d --name sql mysql:8.0.36
[root@Docker ~]# docker ps -l
0cd5a31bb603 mysql:8.0.36 Exited (1)
'状态是已退出'
# 为什么会直接退出呢?
[root@Docker ~]# docker logs sql
2026-04-19 06:15:53+00:00 [ERROR] [Entrypoint]: Database is uninitialized and password option is not specified
# 数据库初始化没有指定密码
You need to specify one of the following as an environment variable: # 你必须从这其中指定一个env
- MYSQL_ROOT_PASSWORD # 指定root密码
- MYSQL_ALLOW_EMPTY_PASSWORD # root密码为空
- MYSQL_RANDOM_ROOT_PASSWORD # 随机root密码
[root@Docker ~]# docker container run \
-e MYSQL_ALLOW_EMPTY_PASSWORD="yes" \
-d \
-p 3306:3306 \
--name mysql-server \
-e MYSQL_DATABASE="wordpress" \
-e MYSQL_USER="jiu" \
-e MYSQL_PASSWORD="oldboy123.com" \
mysql:8.0.36 \
--character-set-server=utf8mb4 \
--collation-server=utf8mb4_unicode_ci \
--default-authentication-plugin=mysql_native_password
# 第一个环境变量是,允许root的密码为空
# 后面是创建一个数据库,和专门的用户及密码
# 再后面是字符集,连接的插件->适配老版本
[root@Docker ~]# docker ps
67598c2 mysql:8.0.36 "docker-entrypoint.s…" Up 3 seconds 0.0.0.0:3306->3306/tcp mysql-server
[root@Docker ~]# docker exec -it mysql-server mysql -uroot
-it # 以交互式的方式进入MySQL
mysql -uroot # 终端执行的命令
'Welcome to the MySQL'
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| sys |
| wordpress |
+--------------------+
mysql> SELECT user,host FROM mysql.user;
'用户也被创建出来了'
+------------------+-----------+
| user | host |
+------------------+-----------+
| jiu | % |
| root | % |
....................
| root | localhost |
+------------------+-----------+
mysql> SHOW GRANTS FOR jiu;
# 我们创建出来jiu这个用户的权限
+----------------------------------------------------+
| Grants for jiu@% |
+----------------------------------------------------+
| GRANT USAGE ON *.* TO `jiu`@`%` |
| GRANT ALL PRIVILEGES ON `wordpress`.* TO `jiu`@`%` |
+----------------------------------------------------+
1)USAGE 是一个特殊的权限,它仅表示允许用户 jiu 连接到 MySQL 服务器
2)但不授予任何实际操作权限(如查询、修改、删除等)
3)这是每个 MySQL 用户都具备的基础连接权限
'基于容器部署mysql-->非常便利'
# run的时候,就把数据库,和用户及权限直接都给分配好了

部署WordPress#

Terminal window
# 确保mysql服务启动成功
[root@Docker ~]# ss -lntup | grep 3306
tcp LISTEN 0 4096 0.0.0.0:3306
tcp LISTEN 0 4096 [::]:3306
[root@Docker ~]# docker search docker.xuanyuan.run/wordpress:6.7.1
wordpress The WordPress rich… 5867 [OK]
[root@Docker ~]# docker pull docker.xuanyuan.run/wordpress:6.7.1
[root@Docker ~]# docker tag docker.xuanyuan.run/wordpress:6.7.1 wordpress:6.7.1
[root@Docker ~]# docker rmi docker.xuanyuan.run/wordpress:6.7.1
[root@Docker ~]# docker images
wordpress:6.7.1 43693c77589b
'他必须得连接到数据库才行'
# 会有很多的环境变量

以下是运行 WordPress 容器时通常需要指定的⚙️==核心环境变量==:

变量名说明
WORDPRESS_DB_HOST数据库主机地址
WORDPRESS_DB_USER数据库用户名
WORDPRESS_DB_PASSWORD数据库密码
WORDPRESS_DB_NAME数据库名称
WORDPRESS_TABLE_PREFIX数据表前缀
Terminal window
docker run -d \
--name my-wordpress \
-p 8080:80 \
-e WORDPRESS_DB_HOST=10.0.0.99:3306 \
-e WORDPRESS_DB_USER=jiu \
-e WORDPRESS_DB_PASSWORD=oldboy123.com \
-e WORDPRESS_DB_NAME=wordpress \
-e WORDPRESS_TABLE_PREFIX=wp_ \
wordpress:6.7.1
Terminal window
[root@Docker ~]# docker ps
c751cdf62326 wordpress:6.7.1 "docker-entrypoint.s…" 2 seconds ago Up 2 seconds 0.0.0.0:8080->80/tcp, [::]:8080->80/tcp my-wordpress
[root@Docker ~]# ss -lnt | grep 8080
LISTEN 0 4096 0.0.0.0:8080
LISTEN 0 4096 [::]:8080

image-20260419153747548
image-20260419153747548

Terminal window
[root@Docker ~]# docker exec -it mysql-server mysql -uroot
mysql> use wordpress;
Database changed
mysql> SHOW TABLES;
+-----------------------+
| Tables_in_wordpress |
+-----------------------+
| wp_commentmeta |
| wp_comments |
| wp_links |
| wp_options |
| wp_postmeta |
| wp_posts |
| wp_term_relationships |
| wp_term_taxonomy |
| wp_termmeta |
| wp_terms |
| wp_usermeta |
| wp_users |
+-----------------------+
# 现在数据库里面已经有很多表信息了

部署Redis#

Terminal window
[root@Docker ~]# docker pull docker.xuanyuan.run/redis:7.2.8
[root@Docker ~]# docker images
redis:7.2.8 bb1b66279bfa
[root@Docker ~]# docker container run -d \
--name redis-server \
-p 6379:6379 \
redis:7.2.8
[root@Docker ~]# ss -lnt | grep 6379
LISTEN 0 4096 0.0.0.0:6379
LISTEN 0 4096 [::]:6379
[root@Docker ~]# docker exec -it redis-server redis-cli
127.0.0.1:6379> keys *
(empty array)
127.0.0.1:6379> SET school oldboyedu
OK
127.0.0.1:6379> SET class kpyun
OK
127.0.0.1:6379> keys *
1) "school"
2) "class"

文章分享

如果这篇文章对你有帮助,欢迎分享给更多人!

容器管理
https://www.kpyun.fun/posts/docker/docker02/
作者
久棹
发布于
2026-02-17
许可协议
CC BY-NC-SA 4.0
Profile Image of the Author
久棹
只要胆子大,天天寒暑假!
公告
欢迎来到久棹的技术小站!本站专注 Linux 运维学习笔记分享,如有问题欢迎交流探讨 🎉
分类
标签
站点统计
文章
98
分类
11
标签
203
总字数
244,453
运行时长
0
最后活动
0 天前
站点信息
构建平台
Local
博客版本
Firefly v6.13.5
文章许可
CC BY-NC-SA 4.0

文章目录