容器管理

容器管理
[TOC]
基本操作
[root@Docker ~]# docker image ls | grep centoscentos: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 ps66ea246de8d9 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 ls87c0cfd3bd45 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# 强制停止当前容器容器即进程
'Docker 容器中进程的关系'🥬我们先把环境清理一下![root@Docker ~]# docker container rm -f $(docker ps -qa)87c0cfd3bd4566ea246de8d9793de8a8f041===================================docker ps -qa # 取出历史所有的容器idrm -f # 强制删除容器-->后面跟容器iddocker ps -qa | xargs docker container rm -f👆和这条命令等价[root@Docker ~]# docker ps -a# 现在一个也没有了===================================[root@Docker ~]# docker run --name v1 centos tail -f /etc/hosts27.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 CMDroot 1 tail -f /etc/hostsroot 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 CMDroot 1 tail -f /etc/hostsroot 19 sleep 60root 25 ps -ef# 除了主进程之外多了一个sleep 60 👆刚开的新进程[root@Docker ~]# ps -ef | grep sleeproot 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=1COMMAND STATUS"tail -f /etc/hosts" Exited (137)# 主进程杀死,容器直接没了(退出)===================================1.容器在启动的时候是有启动命令的 (1)tail -f /etc/hosts (2)sleep 602.一个容器里面可以运行多个进程的# 可以用docker exec创建多个新的进程 (1)docker run → 创建容器和✅️"主进程" (2)docker exec → 在运行的容器中创建新进程 # 新的进程,并非主进程,允许挂!3.所有容器进程 → 都在宿主机上有对应的真实进程# 它俩的进程号不同4.容器的主进程(PID 1)一旦被杀死,整个容器就会停止# 容器中其他的进程也会挂想要让 docker ps 显示完整信息,不再出现 ...,核心秘诀就是加上 --no-trunc 参数
默认情况下,Docker 为了保持终端整洁,会把很长的命令(COMMAND 列)和容器 ID 截断显示
docker top
-
docker top命令查看的是宿主机(Host)视角下的进程信息- 类似于在宿主机执行 ps -ef | grep 命令
- 都是为了过滤出容器内进程—>对应宿主机的==真实进程==
-
docker exec <容器名> ps -ef
- 容器内的虚拟 PID
[root@Docker ~]# docker run --name v1 centos tail -f /etc/hosts# 让它阻塞住'新开一个终端'[root@Docker ~]# ps -ef | grep tailroot 6978 2063 pts/1 docker run --name v1 centos tail -f /etc/hostsroot 7017 6993 ? tail -f /etc/hosts[root@Docker ~]# docker top v1UID PID PPID TTY CMDroot 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 CMDroot 1 0 ? tail -f /etc/hostsroot 19 0 ? sleep 60root 25 0 ? ps -ef[root@Docker ~]# docker top v1"查看宿主机对应的真实PID"UID PID PPID TTY CMDroot 7017 6993 ? tail -f /etc/hostsroot 7255 6993 ? sleep 60✅️很方便,不需要ps -ef | grep过滤了!# 很容易就能看到某个容器对应宿主机的真实PID| 特性 | docker top <容器名> | docker exec <容器名> ps |
|---|---|---|
| 执行位置 | 宿主机 (由 Docker 守护进程查询) | 容器内部 (真正在容器里执行命令) |
| 显示的 PID | 宿主机的真实 PID (如 10311) | 容器内的虚拟 PID (通常是 1, 15, 16…) |
| 依赖环境 | 不需要容器内有 ps 命令 | 容器内必须安装了 ps (如 procps 包) |
[root@Docker ~]# docker run --name web -d -p 81:80 nginx209539aff72e[root@Docker ~]# curl localhost:81<title>Welcome to nginx!</title>[root@Docker ~]# docker exec web ps -efexec failed: unable to start container process: exec: "ps":# 这个nginx容器里面压根就没有这个命令# 自然没有办法查看容器里面的进程[root@Docker ~]# docker top web'但是我们可以看宿主机对应真实的PID'UID PID PPID TTY CMDroot 7425 7402 ? nginx: master process nginx -g daemon off;101 7497 7425 ? nginx: worker process# master就是主进程--->7425[root@Docker ~]# docker ps209539aff72e nginx "/docker-entrypoint.…"[root@Docker ~]# kill -9 7425[root@Docker ~]# docker ps'杀死主进程,容器就退出了'[root@Docker ~]# docker start webweb[root@Docker ~]# docker ps209539aff72e 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 -efUID PID PPID TTY CMDroot 1 0 ? nginx: master process nginx -g daemon off;nginx 22 1 ? nginx: worker processroot 192 0 ? ps -ef'安装完对应的包,就能查看到容器里面的进程了!'===================================root@Docker:/# cat /etc/os-releasePRETTY_NAME="Debian GNU/Linux 13 (trixie)"NAME="Debian GNU/Linux"# Debian系列的操作系统①先换源cat > /etc/apt/sources.list << EOFdeb http://mirrors.ustc.edu.cn/debian/ trixie main contrib non-freedeb http://mirrors.ustc.edu.cn/debian/ trixie-updates main contrib non-freedeb http://mirrors.ustc.edu.cn/debian-security/ trixie-security main contrib non-freeEOF②再升级软件包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 执行后发现没有输入流,很快就结束了
- 容器立即退出的根本原因
- 主进程退出 → 整个容器停止
1)以交互式模式运行"-it"[root@Docker ~]# docker run -it --name v2 centos# 直接进入到容器里面了# @后面是容器id[root@81d3149a35ff /]# hostname -I172.17.0.2[root@81d3149a35ff /]# ps -efUID PID PPID TTY TIME CMDroot 1 0 pts/0 00:00:00 /bin/bashroot 17 1 pts/0 00:00:00 ps -ef# 这次就有TTY终端了--->pts/0以前都是?[root@Docker ~]# docker exec v2 sleep 100'在另一个终端执行睡眠命令'[root@81d3149a35ff /]# ps -efUID PID PPID TTY TIME CMDroot 1 0 pts/0 00:00:00 /bin/bashroot 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 -efUID PID PPID TTY TIME CMDroot 1 0 pts/0 00:00:00 /bin/bashroot 38 1 pts/0 00:00:00 ps -ef# 没有sleep进程了,同时另一个终端也不阻塞了'我们可以在容器的终端里面进行操作和管理'
2)退出容器[root@81d3149a35ff /]# exitexit[root@Docker ~]# docker ps# 没有正在运行的容器[root@Docker ~]# docker ps -a -n=181d3149a35ff centos "/bin/bash" Exited (0)# 它的状态是已退出
3)再次进入容器[root@Docker ~]# docker start v2v2# 我们把v2启动起来[root@Docker ~]# docker ps81d3149a35ff centos "/bin/bash"[root@Docker ~]# docker exec v2 ps -ef# 去看一眼容器里面的进程UID PID TTY CMDroot 1 pts/0 /bin/bashroot 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 CMDroot 1 0 pts/0 00:00:00 /bin/bashroot 21 0 pts/1 00:00:00 /bin/bashroot 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 -efUID PID PPID TTY TIME CMDroot 1 0 pts/0 00:00:00 /bin/bashroot 21 0 pts/1 00:00:00 /bin/bashroot 36 0 ? 00:00:00 ps -ef# 容器中这两个进程都没有停止
5)attach复用连接-->是直接"连接"到容器的主进程(PID 1)[root@Docker ~]# docker attach v2'再次进入到容器中'[root@81d3149a35ff /]# ps -efUID PID PPID TTY TIME CMDroot 1 0 pts/0 00:00:00 /bin/bashroot 21 0 pts/1 00:00:00 /bin/bashroot 42 1 pts/0 00:00:00 ps -ef# 通过ps -ef命令的TTY可以知道,我们现在和主进程在同一个终端里面[root@81d3149a35ff /]# exitexit"也可以用快捷键Ctrl+D进行退出"[root@Docker ~]# docker ps# 没有正在运行的进程'我们刚才复用连接的是主进程'✅️主进程退出-->整个容器直接停止
6)后台运行容器"-d"[root@Docker ~]# docker run -d --name v3 centos2c41e5ee85961[root@Docker ~]# docker ps# 没有正在运行的容器[root@Docker ~]# docker ps -a -n=12c41e5ee8596 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 认为任务完成,立即退出
- ✅ 容器主进程退出 → 整个容器停止
'我们再来试试nginx容器'[root@Docker ~]# docker run -d --name web -p 81:80 nginx:latest67c4c1e120df'并没有设置-i和-t'-->只有-d[root@Docker ~]# docker ps67c4c1e120df 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 是守护进程,会持续运行那么,我们如何才能让Centos容器正确的放在后台运行呢❓️-d -it# 同时使用这些选项"放在后台运行的同时,给输入和伪终端"[root@Docker ~]# docker run -d -it --name v4 centos125bfb32b3f5[root@Docker ~]# docker ps125bfb32b3f5 centos "/bin/bash" 3 seconds ago Up 3 seconds# 这不就成功起来了嘛!# 3s前启动,运行了3s[root@Docker ~]# docker exec v4 ps -efUID PID PPID TTY TIME CMDroot 1 0 pts/0 00:00:00 /bin/bashroot 15 0 ? 00:00:00 ps -ef# 我们去容器里面看一下'主进程是有伪终端的-->pts/0'===================================怎么进去呢❓️# 两种方法 (1)docker exec -it v4 /bin/bash (2)docker attach v41)重新开一个进程,以交互式终端的方式进入# 当然也新开一个伪终端[root@Docker ~]# docker exec -it v4 /bin/bash[root@125bfb32b3f5 /]# ps -efUID PID PPID TTY TIME CMDroot 1 0 pts/0 00:00:00 /bin/bashroot 21 0 pts/1 00:00:00 /bin/bashroot 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 -efUID PID TTY CMDroot 1 pts/0 /bin/bashroot 21 pts/1 /bin/bashroot 42 pts/0 ps -ef# 来到了主进程的终端--->pts/0[root@125bfb32b3f5 /]# kill -9 21# 可以直接把pts/1伪终端的进程强制杀死[root@125bfb32b3f5 /]# ps -efUID PID TTY CMDroot 1 pts/0 /bin/bashroot 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 -fDeleted Containers:67c4c1e120dfbe52c41e5ee85961fc81d3149a35ff3a8414f1c07ac3551f[root@Docker ~]# docker ps125bfb32b3f5 centos "/bin/bash" 31 minutes ago Up 31 minutes'正在运行的容器并没有受到影响'Nginx容器详解
1)正常运行[root@Docker ~]# docker run --name web -d -p 81:80 nginx2f5f9aad98c9[root@Docker ~]# curl localhost:81<title>Welcome to nginx!</title># 成功拉取到页面[root@Docker ~]# docker exec web ps -efexec 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 -efbash: ps: command not found# 它是精简镜像,并且主要的目的就是跑nginx服务,所以很多命令并没有root@2f5f9aad98c9:/# cat /etc/hosts......172.17.0.2 2f5f9aad98c9root@2f5f9aad98c9:/# lsbin dev home lib64 mnt proc run srv tmp varboot 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 localhostHello World'成功更改主页'
2)容器导出-->"export"docker export 容器id > 目标名.tar.gz-o: 也是可以的# 作用:将指定容器的文件系统(即容器运行时的所有文件)打包成一个 tar 归档文件root@2f5f9aad98c9:/# exitexit'需要在宿主机操作'[root@Docker ~]# docker export web -o mynginx-v1.tar.gz[root@Docker ~]# lsmynginx-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 imagesmyweb 1.0 58456a1acc71[root@test ~]# docker run --name web -d -p 82:80 myweb:1.0docker: Error response from daemon: no command specified.# 没有特殊的启动命令[root@test ~]# docker run --name web -d -p 82:80 myweb:1.0 /bin/bash# 那我们就给一个启动命令 /bin/bash2656467d8[root@test ~]# docker ps# 但是容器并没有启动起来启动完即刻退出'/bin/bash 需要有标准的输入输出才行'[root@test ~]# docker run --name web-test -d -it -p 82:80 myweb:1.0 /bin/bash2f554a82dbdf[root@test ~]# docker attach web-testroot@2f554a82dbdf:/# curl localhostcurl: (7) Failed to connect to localhost port 80 after 0 ms: Could not connect to server# 没有办法拉取到页面这是为什么呢???文件系统 vs 元数据
关键点:docker export 导出的只是容器的文件系统快照,它不包含原始镜像的元数据,例如:
- 镜像的历史构建层
- 环境变量 (
ENV) - 端口暴露 (
EXPOSE) - 默认启动命令 (
CMD) 等配置

🧅 镜像的“千层饼”结构
你可以把一个 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)只描述配置,所以 SIZE 是 0B
✅️而像 RUN 这样的元数据,因为它执行了安装软件的操作,所以它关联的层就有 85.4MB 的大小

- 上面镜像层中的文件 ==app2.0== 覆盖了下层 ==app1.0==
- 相当于做了版本升级
- 如果所需要的某一层已经存在了,就不需要下载了
docker export 做的事情非常“粗暴”:
- 它会把所有层(千层饼)压扁、合并成一个整体
- 它不管你原来有多少层,也不管每一层是怎么来的
- 它只拿走合并后的最终文件系统
- 也就是把所有层叠加后,容器里能看到的==所有文件和目录==
- 这就是为什么导出的
tar包大小和容器实际占用的磁盘空间差不多
- 它把所有“说明书”(元数据)全部扔掉
CMD、ENV、EXPOSE、LABEL以及每一层的构建历史,统统不包含在tar包里
所以,docker export 导出的文件,就像一个没有说明书、被压成一块的饼干
它的“内容物”(文件)都在,所以体积没变
但你已经不知道它原来是怎么做的,也不知道该怎么“启动”它了
| 对比项 | docker history / 原始镜像 | docker export 导出的 tar 包 |
|---|---|---|
| 结构 | 多层叠加的“千层饼” | 压扁合并的“一张饼” |
| 文件系统 | 由所有层叠加而成 | 只包含最终合并后的文件 |
| 元数据 | 完整保留 (CMD, ENV, 构建历史等) | 全部丢失 |
| 包含内容 | 文件 + 所有“说明书” | 只有文件 |
📥 import 导入为镜像
作用:将 tar 文件的内容作为一个新的文件系统层,并创建一个新的 Docker 镜像
- docker import -m “描述信息” 压缩包 <新镜像名>:
关键点:
docker import会创建一个全新的、扁平化的镜像,不包含任何历史层-m参数可以为这次导入操作添加一条提交信息,方便记录- 由于原始元数据已丢失,这个新镜像没有默认的启动命令
- 需要在运行它时手动指定要执行的命令
| 特性 | docker export / docker import | docker save / docker load |
|---|---|---|
| 操作对象 | 容器 (Container) | ==镜像 (Image)== |
| 保留元数据 | 否,只保留文件系统 | 是,保留所有层、标签和历史 |
| 适用场景 | 快速迁移容器状态,创建轻量级==基础镜像== | 完整备份或迁移镜像,保留所有信息 |
[root@test ~]# docker import -m "从容器导入" mynginx-v1.tar.gz myweb:1.0sha256:5fced15845fb[root@test ~]# docker imagesmyweb 1.0 5fced15845fb[root@test ~]# docker history myweb:1.0IMAGE CREATED BY SIZE COMMENT5fced15845fb 159MB 从容器导入"扁平化的镜像,不包含任何历史层"[root@test ~]# docker run -d -p 81:80 --name test myweb:1.0docker: 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 ps4a2e407c08ab myweb:1.0 "nginx -g 'daemon of…"'[root@test ~]# curl localhost:81Hello 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.0sha256:588b2bbdb508-c: 指定 CMD (启动命令)[root@test ~]# docker run -d -p 81:80 --name test myweb:1.0# 并没有指定启动命令[root@test ~]# curl localhost:81Hello World'成功拉取到了'[root@test ~]# docker history myweb:1.0IMAGE CREATED BY SIZE COMMENT588b2bbdb508 159MB 从容器导入# 并没有启动命令在export导出的时候,就被压成一层===================================`docker history` 主要展示的是“镜像层”的构建历史,而不是“镜像配置”的内容-c 参数--->写入了这个新镜像的配置 (Config) 中[root@test ~]# docker inspect myweb:1.0"Cmd": [ "nginx", "-g", "daemon off;"# 在这里面可以看到!元数据对比
'通过查看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:latestlinux===================================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 commit | docker export/import |
|---|---|---|
| 元数据保留 | ✅ 保留 | ❌ 丢失 |
| 分层结构 | ✅ 保持分层 | ❌ 扁平化 |
| 文件系统 | 包含所有变更 | 仅文件系统快照 |
| 历史记录 | 保留基础镜像历史 | 丢弃所有历史记录 |
| 适用场景 | ==保存容器状态== | ==制作基础镜像== |
[root@Docker ~]# docker run -d --name web -p 81:80 nginx8b7de7077[root@Docker ~]# docker exec -it web /bin/bashroot@8b7de7077c07:/# curl localhost<title>Welcome to nginx!</title>root@8b7de7077c07:/# echo Hello World > /usr/share/nginx/html/index.htmlroot@8b7de7077c07:/# curl localhostHello World[root@Docker ~]# docker commit web my-web:1.0sha256:2668ca268ea5[root@Docker ~]# docker imagesnginx:latest 7f0adca1fc6cmy-web:1.0 2668ca268ea5👆是我们刚提交的镜像,"两个镜像id都不同"[root@Docker ~]# docker history nginx:latest7f0adca1fc6c 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.02668ca268ea5 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 imagesmy-web 1.0 a439601f00e2[root@test ~]# docker history my-web:1.0a439601f00e2 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:81Hello Worldcp拷贝命令
docker cp 的核心作用就是打破容器与宿主机之间的隔离,实现文件的双向复制
- 这个命令是在宿主机的终端中执行的,不需要进入容器内部
- 拷贝是一个手动的过程,未来我们使用 -v 容器卷的技术,可以实现自动同步
| 传输方向 | 命令格式 |
|---|---|
| 宿主机 → 容器 | docker cp <宿主机路径> <容器ID/名称>:<容器内路径> |
| 容器 → 宿主机 | docker cp <容器ID/名称>:<容器内路径> <宿主机路径> |
[root@Docker ~]# echo kpyun > test.md[root@Docker ~]# lstest.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:/homeSuccessfully copied 6B (transferred 2.05kB) to v1:/home# 把本地的测试文件拷贝至容器中[root@Docker ~]# docker cp v1:/home/v1.md /rootSuccessfully 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]# exitexit传入环境变量
-e "传递环境变量"
[root@Docker ~]# docker run -d -it -e SCHOOL=oldboy --name v1 centos[root@Docker ~]# docker exec v1 envPATH=/usr/local/sbin:/usr/local/bin...HOSTNAME=82f06844dfc9SCHOOL=oldboy👆就是我们传递的环境变量HOME=/root[root@Docker ~]# docker attach v1'进入到容器里面'[root@82f06844dfc9 /]# env | grep SCHOOLSCHOOL=oldboy# 同样可以过滤出来日志信息
docker logs --> "查看日志信息"-f: # 实时跟踪日志输出-n=num: # 只显示最后 num 行日志-t: # 显示时间戳--since: # 显示自某时刻之后的日志👆面试题,最近20分钟的日志 --> 20m[root@Docker ~]# docker run -d --name web -p 81:80 nginx480a3d495bee[root@Docker ~]# docker ps -l480a3d495bee 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) | 不重启 🛑 | 不启动 🔴 正常退出后 |
--restart 重启策略===============================always # 一直重启unless-stopped # 只有手动stop了,才不启动on-failure # 失败了重启,正常退出不重启==异常退出(Exited 非0):==(如 Exited 137)
- 容器挂了(进程崩溃)
- 比如程序报错、内存溢出、或者被
kill -9干掉
- 比如程序报错、内存溢出、或者被
注意: 你手动执行 docker stop,它的状态码也是 Exited 137
-
但它不算异常退出
-
在 Docker 眼里算作“正常休假”,所有策略都不会自动重启它
-
==正常退出(Exited 0)== 启动命令退出(如
sleep 10结束) -
==重启Docker服务== ---> 执行
systemctl restart docker- 模拟服务器断电
1)环境清理[root@Docker ~]# docker rm -f $(docker ps -aq)
2)拉取镜像[root@Docker ~]# docker pull docker.xuanyuan.run/alpine:3.20.2[root@Docker ~]# docker imagesalpine: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 psCONTAINER ID IMAGE STATUS NAMESc0a126fc0013 alpine:3.20.2 Up 4 minutes c5-on-failure-max43cdba8d6738 alpine:3.20.2 Up 4 minutes c4-on-failurece514fe3dd72 alpine:3.20.2 Up 4 minutes c3-unless-stopped5db38a13c1cc alpine:3.20.2 Up 4 minutes c2-alwaysd8e1ad8954d0 alpine:3.20.2 Up 5 minutes c1-no===============================🌰直接restart重启容器[root@Docker ~]# systemctl restart docker[root@Docker ~]# docker ps -aCONTAINER ID IMAGE STATUS NAMESc0a126fc0013 alpine:3.20.2 Up 9 seconds c5-on-failure-max43cdba8d6738 alpine:3.20.2 Up 9 seconds c4-on-failurece514fe3dd72 alpine:3.20.2 Up 9 seconds c3-unless-stopped5db38a13c1cc alpine:3.20.2 Up 9 seconds c2-alwaysd8e1ad8954d0 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 -aSTATUSExited (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 -aCONTAINER ID IMAGE STATUS NAMESc0a126fc0013 alpine:3.20.2 Up 9 seconds c5-on-failure-max43cdba8d6738 alpine:3.20.2 Up 9 seconds c4-on-failurece514fe3dd72 alpine:3.20.2 Exited (137) c3-unless-stopped5db38a13c1cc alpine:3.20.2 Up 9 seconds c2-alwaysd8e1ad8954d0 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 CMDroot 4689 4662 pts/0 00:00:00 /bin/sh# 只有一个,4689就是它的主进程对应的PID[root@Docker ~]# docker inspect -f "{{.State.Pid}}" c1-no4689'当然我们也可以用inspect去查看'✅️.State.Pid 的含义: 🌿这个字段特指容器启动时运行的第一个进程 🌿也就是 PID 为 1 的主进程-->在宿主机上对应的 进程ID[root@Docker ~]# docker inspect -f "{{.State.Pid}}" `docker ps -aq`44724487462544644689# 把所有容器的主进程取出来[root@Docker ~]# docker container inspect -f {{.State.Pid}} `docker ps -aq` | xargs kill -9'都强制杀死'[root@Docker ~]# docker ps -ac0a126fc0013 alpine:3.20.2 Up 9 seconds c5-on-failure-max43cdba8d6738 alpine:3.20.2 Up 9 seconds c4-on-failurece514fe3dd72 alpine:3.20.2 Up 9 seconds c3-unless-stopped5db38a13c1cc alpine:3.20.2 Up 9 seconds c2-alwaysd8e1ad8954d0 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 -ac0a126fc0013 alpine:3.20.2 Exited (137) c5-on-failure-max43cdba8d6738 alpine:3.20.2 Up 9 seconds c4-on-failurece514fe3dd72 alpine:3.20.2 Up 9 seconds c3-unless-stopped5db38a13c1cc alpine:3.20.2 Up 9 seconds c2-alwaysd8e1ad8954d0 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 10docker run -d -it --name c2-always --restart always alpine:3.20.2 sleep 10docker run -d -it --name c3-unless-stopped --restart unless-stopped alpine:3.20.2 sleep 10docker run -d -it --name c4-on-failure --restart on-failure alpine:3.20.2 sleep 10docker run -d -it --name c5-on-failure-max --restart on-failure:3 alpine:3.20.2 sleep 10[root@Docker ~]# docker psCONTAINER ID COMMAND STATUS NAMESe140e3afe0f6 "sleep 10" Up 2 seconds c5-on-failure-max0740e7cb35a7 "sleep 10" Up 3 seconds c4-on-failure06e01a832866 "sleep 10" Up 3 seconds c3-unless-stopped5a010d061926 "sleep 10" Up 3 seconds c2-alwaysa1d86c69344d "sleep 10" Up 3 seconds c1-no'等10s再次查看'[root@Docker ~]# docker ps -aCONTAINER ID COMMAND STATUS NAMESe140e3afe0f6 "sleep 10" Exited (0) c5-on-failure-max0740e7cb35a7 "sleep 10" Exited (0) c4-on-failure06e01a832866 "sleep 10" Up 9 seconds c3-unless-stopped5a010d061926 "sleep 10" Up 9 seconds c2-alwaysa1d86c69344d "sleep 10" Exited (0) c1-no===============================🌰正常退出后,再手动stop,在重启服务[root@Docker ~]# docker stop -t 0 $(docker ps -aq)[root@Docker ~]# docker ps -aCONTAINER ID COMMAND STATUS NAMESe140e3afe0f6 "sleep 10" Exited (0) c5-on-failure-max0740e7cb35a7 "sleep 10" Exited (0) c4-on-failure06e01a832866 "sleep 10" Exited (137) c3-unless-stopped5a010d061926 "sleep 10" Exited (137) c2-alwaysa1d86c69344d "sleep 10" Exited (0) c1-no'后面是为了比较always和unless-stopped'⚠️on-failure在正常退出后,就不会启动了[root@Docker ~]# systemctl restart docker[root@Docker ~]# docker ps -aCONTAINER ID COMMAND STATUS NAMESe140e3afe0f6 "sleep 10" Exited (0) c5-on-failure-max0740e7cb35a7 "sleep 10" Exited (0) c4-on-failure06e01a832866 "sleep 10" Exited (137) c3-unless-stopped5a010d061926 "sleep 10" Up 5 seconds c2-alwaysa1d86c69344d "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) |
[root@Docker ~]# docker create --name v1 -it alpine:3.20.2[root@Docker ~]# docker ps -ac6ebb753e991 alpine:3.20.2 "/bin/sh" Created[root@Docker ~]# docker start v1[root@Docker ~]# docker psc6ebb753e991 alpine:3.20.2 "/bin/sh" Up 5 seconds"由Created --> Up"[root@Docker ~]# docker pause v1[root@Docker ~]# docker psc6ebb753e991 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 psc6ebb753e991 alpine:3.20.2 "/bin/sh" Up 5 seconds[root@Docker ~]# docker exec -it v1 /bin/bashexec: "/bin/bash": stat /bin/bash: no such file or directory'因为alpine它是最简镜像,没有/bin/bash'✅️用sh[root@Docker ~]# docker exec -it v1 sh/ # whoamiroot/ # exit项目部署案例
部署mysql服务
[root@Docker ~]# docker pull docker.xuanyuan.run/mysql:8.0.36[root@Docker ~]# docker imagesdocker.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 imagesmysql:8.0.36 a53272402242[root@Docker ~]# docker run -d --name sql mysql:8.0.36[root@Docker ~]# docker ps -l0cd5a31bb603 mysql:8.0.36 Exited (1)'状态是已退出'# 为什么会直接退出呢?[root@Docker ~]# docker logs sql2026-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 ps67598c2 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 # 以交互式的方式进入MySQLmysql -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
# 确保mysql服务启动成功[root@Docker ~]# ss -lntup | grep 3306tcp LISTEN 0 4096 0.0.0.0:3306tcp LISTEN 0 4096 [::]:3306[root@Docker ~]# docker search docker.xuanyuan.run/wordpress:6.7.1wordpress 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 imageswordpress:6.7.1 43693c77589b'他必须得连接到数据库才行'# 会有很多的环境变量以下是运行 WordPress 容器时通常需要指定的⚙️==核心环境变量==:
| 变量名 | 说明 |
|---|---|
WORDPRESS_DB_HOST | 数据库主机地址 |
WORDPRESS_DB_USER | 数据库用户名 |
WORDPRESS_DB_PASSWORD | 数据库密码 |
WORDPRESS_DB_NAME | 数据库名称 |
WORDPRESS_TABLE_PREFIX | 数据表前缀 |
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[root@Docker ~]# docker psc751cdf62326 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 8080LISTEN 0 4096 0.0.0.0:8080LISTEN 0 4096 [::]:8080
[root@Docker ~]# docker exec -it mysql-server mysql -urootmysql> 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
[root@Docker ~]# docker pull docker.xuanyuan.run/redis:7.2.8[root@Docker ~]# docker imagesredis: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 6379LISTEN 0 4096 0.0.0.0:6379LISTEN 0 4096 [::]:6379[root@Docker ~]# docker exec -it redis-server redis-cli127.0.0.1:6379> keys *(empty array)127.0.0.1:6379> SET school oldboyeduOK127.0.0.1:6379> SET class kpyunOK127.0.0.1:6379> keys *1) "school"2) "class"文章分享
如果这篇文章对你有帮助,欢迎分享给更多人!



