Docker:镜像的运行实体-Docker Container

Docker:镜像的运行实体-Docker Container

一.认识docker容器

通俗的来说,如果说镜像是我们在C++/Java中已经写好的一个类,那么容器就是在运行时通过类实例化的一个对象。

所以容器是镜像的运行实体。镜像是静态的只读文件,而容器带有运行时需要的可写文件层,并且容器中的进程属于运行状态。即容器运行着真正的应用进程。容器有初建、运行、停止、暂停和删除五种状态。

虽然容器的本质是主机上运行的一个进程,但是容器有自己独立的命名空间隔离和资源限制 。也就是说,在容器内部,无法看到主机上的进程、环境变量、网络等信息 ,这是容器与直接运行在主机上进程的本质区别。

容器是基于镜像创建的可运行实例,并且单独存在,一个镜像可以创建出多个容器,就像我们编程语言中一个类能实例化多个不同名称的对象一样。运行容器化环境时,实际上是在容器内部创建该文件系统的读写副本。 这将添加一个容器层,该层允许修改镜像的整个副本。

容器的生命周期

容器的生命周期是容器可能处于的状态。

  1. created:初建状态
  2. running:运行状态
  3. stopped:停止状态
  4. paused: 暂停状态
  5. deleted:删除状态

各生命周期之间的转换关系如图所示:

docker create : 创建容器后,不立即启动运行,容器进入初建状态;
docker run : 创建容器,并立即启动运行,进入运行状态;
docker start : 容器转为运行状态;
docker stop : 容器将转入停止状态;
docker kill : 容器在故障(死机)时,执行 kill(断电),容器转入停止状态,这种操作容易丢失数据,除非必要,否则不建议使用;
docker restart : 重启容器,容器转入运行状态;
docker pause : 容器进入暂停状态;
docker unpause : 取消暂停状态,容器进入运行状态;
docker rm : 删除容器,容器转入删除状态。
killed by out-of-memory (因内存不足被终止通常是因为程序内存泄漏导致的 ) :宿主机内存被耗尽,也被称为 OOM :非计划终止这时需要杀死最吃内存的容器,需要注意此时杀死容器的不是docker引擎而是操作系统。
container process exitde异常终止,如果是非预期的异常则大概率是因为代码写的有问题):出现容器被终止后,将进入 Should restart?选择操作:

  • yes 需要重启,容器执行 start 命令,转为运行状态。
  • no 不需要重启,容器转为停止状态。

需要注意的是只有设置了--restart 参数的容器 , Docker Daemon 才会去尝试启动,否则容器会保持停止状态。

对于容器暂停:Docker"剥夺"了此容器的 CPU 资源。而其他资源,如 Memory 资源、 Network 资源等还保留未动。如此一来,失去了 CPU 资源的进程,是不会被主机内核系统所调度的,所以此容就处于"冰封"状态。

docker容器相关常用(较为关键)的命令清单

命令 别名 功能 备注
docker create docker container create 创建容器
docker run docker container run 运行容器 必须掌握
docker attach docker container attach 连接到正在运行中的容器
docker commit docker container commit 将容器提交为镜像 必须掌握
docker cp docker container cp 在容器和宿主机之间拷贝 必须掌握
docker diff docker container diff 检查容器里文件结构的更改
docker exec docker container exec 在运行的容器中执行命令 必须掌握
docker export docker container export 将容器导出为 tar
docker container inspect 查看容器详细信息 必须掌握
docker kill docker container kill 杀死容器 必须掌握
docker logs docker container logs 查看日志 必须掌握
docker ps docker container ls, docker container list, docker container ps 查看正在运行的容器 必须掌握
docker pause docker container pause 暂停容器进程
docker port docker container port 查看容器的端口映射
docker container prune 删除停止的容器
docker rename docker container rename 重命名容器
docker restart docker container restart 重启容器 必须掌握
docker rm docker container rm, docker container remove 删除容器 必须掌握
docker start docker container start 启动容器 必须掌握
docker stats docker container stats 查看资源占用信息 必须掌握
docker stop docker container stop 停止容器 必须掌握
docker top docker container top 查看某个容器的进程信息 必须掌握
docker unpause docker container unpause 继续运行容器
docker update docker container update 更新容器配置
docker wait docker container wait 阻止一个或多个容器停止,然后打印退出代码

二.docker容器命令认识与简单使用

2.1docker create

docker create
功能

创建一个新的容器但不启动它
语法

bash 复制代码
docker create [OPTIONS] IMAGE [COMMAND] [ARG...]

别名

bash 复制代码
docker container create

关键参数

  • -i: 以交互模式运行容器,通常与 -t 同时使用;
  • -P: 随机端口映射,容器内部端口随机映射到主机的端口
  • -p: 指定端口映射,格式为: 主机(宿主)端口:容器端口
  • -t: 为容器重新分配一个伪输入终端,通常与 -i 同时使用;
  • --name="nginx-lb": 为容器指定一个名称;
  • -h "mars": 指定容器的 hostname;
  • -e username="ritchie": 设置环境变量;
  • --cpuset-cpus="0-2" or --cpuset-cpus="0,1,2": 绑定容器到指定 CPU 运行;
  • -m :设置容器使用内存最大值;
  • --network="bridge": 指定容器的网络连接类型;
  • --link=[]: 添加链接到另一个容器;
  • --volume , -v: 绑定一个卷
  • --rm :shell 退出的时候自动删除容器○ --restart:自动重启

它的关键参数与docker run几乎相同,不过相比于docker run。如果说docker run是走了发动汽车全套流程,那么docker create就是缺了最后一步的踩油门启动汽车,我们来看个样例,比如我现在有一个nginx镜像,我用这个镜像去 run一个nginx容器并映射其端口80到主机的8080

bash 复制代码
knd@VM-12-9-ubuntu:~$ sudo docker ps -a
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES
knd@VM-12-9-ubuntu:~$ sudo docker run -d --name=nginx1 -p 8080:80 nginx:1.29.4
1129499f7390d7c1c476c056d66f0ca775da5977206abe6fcb811462a52d8ecb
knd@VM-12-9-ubuntu:~$ sudo docker ps
CONTAINER ID   IMAGE          COMMAND                  CREATED         STATUS         PORTS                                     NAMES
1129499f7390   nginx:1.29.4   "/docker-entrypoint...."   7 seconds ago   Up 6 seconds   0.0.0.0:8080->80/tcp, [::]:8080->80/tcp   nginx1

如果我们这里直接在run一个nginx给相同的参数当然会直接报错,但是create不会:

bash 复制代码
knd@VM-12-9-ubuntu:~$ sudo docker create --name=nginx -p 8080:80 --name=nginx2 nginx:1.29.4 
0b53266992c3db452a5cca6f2c114825efcd987e70fbc06677b0fdad99b72d60

当然如果你让他start起来就肯定会显示端口被占用从而报错退出了:

bash 复制代码
knd@VM-12-9-ubuntu:~$ sudo docker start nginx2
Error response from daemon: failed to set up container networking: driver failed programming external connectivity on endpoint nginx2 (2f77ba3715e2108425121fd5d872a4887b6b7852095234077a73a5da9dc49f2c): Bind for 0.0.0.0:8080 failed: port is already allocated
failed to start containers: nginx2

2.2docker logs

docker logs
功能

查看容器日志
语法

bash 复制代码
docker logs [OPTIONS] CONTAINER

别名

bash 复制代码
docker container logs

关键参数

  • -f ,--follow: 跟踪日志输出
  • --since :显示某个开始时间的所有日志
  • -t,--timestamps : 显示时间戳
  • -n, --tail :仅列出最新 N 条容器日志

比如说我现在想要跟踪一个已经启动了的nginx服务的日志:

那就直接加上-f选项即可:

bash 复制代码
knd@VM-12-9-ubuntu:~$ sudo docker logs -f nginx1
bash 复制代码
2025/12/22 09:09:18 [error] 29#29: *12 open() "/usr/share/nginx/html/favicon.ico" failed (2: No such file or directory), client: 39.144.24.67, server: localhost, request: "GET /favicon.ico HTTP/1.1", host: "111.231.81.4:8080", referrer: "http://111.231.81.4:8080/"
39.144.24.67 - - [22/Dec/2025:09:09:18 +0000] "GET /favicon.ico HTTP/1.1" 404 555 "http://111.231.81.4:8080/" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36 Edg/124.0.2478.87" "-"
39.144.24.67 - - [22/Dec/2025:09:10:07 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36 Edg/124.0.2478.87" "-"
39.144.24.67 - - [22/Dec/2025:09:10:08 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36 Edg/124.0.2478.87" "-"

如果想要看某个时间点之后的所有日志,可以使用--since选项:

比如我想要看两分钟之前的时间点之后的日志:

bash 复制代码
knd@NightCode:~$ sudo docker logs nginx1 --since 2m
20.65.193.148 - - [22/Dec/2025:09:14:35 +0000] "GET / HTTP/1.1" 200 615 "-" "Mozilla/5.0 zgrab/0.x" "-"
20.65.193.148 - - [22/Dec/2025:09:14:35 +0000] "MGLNDD_111.231.81.4_8080" 400 157 "-" "-" "-"

或者两个小时之前的时间点之后的日志:

bash 复制代码
knd@NightCode:~$ sudo docker logs nginx1 --since 2h
141.98.11.140 - - [22/Dec/2025:07:36:47 +0000] "\x16\x03\x01\x00\xDA\x01\x00\x00\xD6\x03\x03\xE2\xA9V\x85\xE9(\x97\xBC\x07\xE1!\xBB\xEAu\x9D\xCDM\x1FQ\xC6@\xDB\x9C}\x8A\x9E#N\xA3\xF5\xF0V \xBB\xD0C2\x17|\xA94\xF8\x8
...

或者是指定时间点之后的日志:

bash 复制代码
knd@NightCode:~$ sudo docker logs nginx1 --since "2099-12-22T17:18:00Z"
bash 复制代码
knd@NightCode:~$ sudo docker logs nginx1 --since "2016-12-22T17:18:00Z"
/docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
/docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/

2.3docker attach

docker attach

连接到正在运行中的容器。
语法

bash 复制代码
docker attach [OPTIONS] CONTAINER 

别名

bash 复制代码
 docker container attach 

关键参数

  • --sig-proxy:是否将所有信号代理,默认是true,如果设置为false,退出的话不会影响容器,否则退出会导致容器退出。

这个参数一般不是很常用啊,这里我们举个例子演示一下即可:

比如说我现在有一个nginx容器在跑,我直接attach进去然后ctrl+c会导致容器退出:

bash 复制代码
knd@NightCode:~$ sudo docker attach nginx1
^C2025/12/22 09:26:39 [notice] 1#1: signal 2 (SIGINT) received, exiting
2025/12/22 09:26:39 [notice] 30#30: exiting
2025/12/22 09:26:39 [notice] 29#29: exiting
...
knd@NightCode:~$ sudo docker ps
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES

如果我们不想让退出信号给到容器内,那就可以加上--sig-proxy选项并将起设置为false:

bash 复制代码
knd@NightCode:~$ sudo docker start nginx1
nginx1
knd@NightCode:~$ sudo docker attach --sig-proxy=false nginx1
^C^C
got 3 SIGTERM/SIGINTs, forcefully exiting
knd@NightCode:~$ sudo docker ps
CONTAINER ID   IMAGE          COMMAND                  CREATED       STATUS              PORTS                                     NAMES
1129499f7390   nginx:1.29.4   "/docker-entrypoint...."   2 hours ago   Up About a minute   0.0.0.0:8080->80/tcp, [::]:8080->80/tcp   nginx1

2.4docker exec

docker exec

docker exec
功能

在容器中执行命令
语法

bash 复制代码
docker exec [OPTIONS] CONTAINER COMMAND [ARG...] 

别名

bash 复制代码
docker container exec 

关键参数

  • -d :分离模式: 在后台运行
  • -i :即使没有附加也保持STDIN 打开
  • -t :分配一个伪终端
  • -e :设置环境变量
  • -u,--user :指定用户 "<name|uid>[:<group|gid>]"
  • -w,--workdir:指定工作目录

一般来说这个命令经常与-it配合bash共同使用来进入容器进行相关操作,比如我容器内部需要ffmpeg去支持流媒体相关的处理啦或者缺依赖了什么的,比如我此时想要进容器给他安装一个busybox方便我们进行命令行操作:

bash 复制代码
knd@NightCode:~$ sudo docker exec -it nginx1 /bin/bash
root@1129499f7390:/# ls 
bin   dev                  docker-entrypoint.sh  home  lib64  mnt  proc  run   srv  tmp  var
boot  docker-entrypoint.d  etc                   lib   media  opt  root  sbin  sys  usr
root@1129499f7390:/# exit
exit

这里我就只ls下看看效果就行了(没预料到里面没有sudo命令)。

如果说我想要进去之后就直接在某个目录下,可以加上-w选项:

bash 复制代码
knd@NightCode:~$ sudo docker exec -it -w /etc nginx1 bash
root@1129499f7390:/etc# exit
exit

如果我们不想以root用户进入容器内执行操作,也可以加上-u选项指定我们进去之后想要使用的用户:

bash 复制代码
knd@NightCode:~$ sudo docker exec -it nginx1 cat /etc/passwd  
root:x:0:0:root:/root:/bin/bash                               
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
...
nginx:x:101:101:nginx user:/nonexistent:/bin/false

可以看到nginx容器中有一个名为nginx的用户,我们使用他去执行bash:

bash 复制代码
knd@NightCode:~$ sudo docker exec -it -u nginx nginx1 /bin/bash
nginx@1129499f7390:/$ whoami
nginx
nginx@1129499f7390:/$ exit
exit

其他的基本上可以参考docker run哪里,效果差不多。

2.5docker start与docker stop

docker start
功能

启动停止的容器
语法

bash 复制代码
docker start [OPTIONS] CONTAINER [CONTAINER...] 

别名

bash 复制代码
docker container start 

docker stop
功能

停止运行的容器
语法

bash 复制代码
 docker stop [OPTIONS] CONTAINER [CONTAINER...]

别名

bash 复制代码
 docker container stop 

关键参数

  • -s :发送的信号

这两个命令基本是配合使用的,一个负责容器启动一个进行停止,看一个简单的例子就明白了:

bash 复制代码
knd@NightCode:~$ sudo docker start nginx1
nginx1
knd@NightCode:~$ sudo docker ps
CONTAINER ID   IMAGE          COMMAND                  CREATED       STATUS         PORTS                                     NAMES
1129499f7390   nginx:1.29.4   "/docker-entrypoint...."   3 hours ago   Up 8 seconds   0.0.0.0:8080->80/tcp, [::]:8080->80/tcp   nginx1
knd@NightCode:~$ sudo docker stop nginx1
nginx1
knd@NightCode:~$ sudo docker ps
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES

SIGTERM是让进程终止的信号,而docker stop默认发的就是这个信号,是最温柔的形式请求进程退出,可以±t定时让进程退出(其他信号可以自己进行尝试):

他这个单位默认是s啊,但是应该是nginx本身设定了更短的超时时间导致一运行stop -t命令就立马退出了,所以这里看不出来,可以尝试用其他的命令试下

bash 复制代码
knd@NightCode:~$ sudo docker start nginx1
nginx1
knd@NightCode:~$ sudo docker stop -t 10000 nginx1
nginx1
knd@NightCode:~$ sudo docker ps
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES

2.6docker restart

docker restart
功能

重启容器
语法

bash 复制代码
docker restart [OPTIONS] CONTAINER [CONTAINER...] 

别名

bash 复制代码
docker container restart 

关键参数

  • -s :发送信号

这个命令发送的是SIGTEGM,默认让容器优雅的退出,我们可以借助nginx容器的日志来看下:

bash 复制代码
#A终端
knd@NightCode:~$ sudo docker restart nginx1
nginx1
bash 复制代码
#B终端
knd@NightCode:~$ sudo docker logs -f -n 5 nginx1
2025/12/23 09:20:35 [notice] 1#1: signal 3 (SIGQUIT) received, shutting down
2025/12/23 09:20:35 [notice] 22#22: gracefully shutting down

gracefully就是优雅的意思,此时nginx是处理完所有需要清理的资源之后才退出的。当然你也可以加上-t选项指定重启需要的时间。

2.7docker kill

docker kill
功能

强制退出容器
语法

bash 复制代码
docker kill [OPTIONS] CONTAINER [CONTAINER...] 

别名

bash 复制代码
docker container kill 

关键参数

  • -s :发送的信号

注意事项:

Docker stop发送的是SIGTERM 信号,docker kill发送的是SIGKILL 信号

我们还是以刚刚的看日志的方式进行验证:

bash 复制代码
#A
knd@NightCode:~$ sudo docker stop nginx1
knd@NightCode:~$ sudo docker kill nginx1
bash 复制代码
#B
knd@NightCode:~$ sudo docker logs -n 5 -f nginx1
...
2025/12/23 09:28:08 [notice] 22#22: gracefully shutting down
2025/12/23 09:28:08 [notice] 23#23: gracefully shutting down
2025/12/23 09:28:08 [notice] 24#24: gracefully shutting down
knd@NightCode:~$ sudo docker logs -n 5 -f nginx1
2025/12/23 09:30:07 [notice] 1#1: start worker processes
2025/12/23 09:30:07 [notice] 1#1: start worker process 22
2025/12/23 09:30:07 [notice] 1#1: start worker process 23
2025/12/23 09:30:07 [notice] 1#1: start worker process 24
2025/12/23 09:30:07 [notice] 1#1: start worker process 25
knd@NightCode:~$ 

可以看到nginx1还未来得及进行任何处理直接就被强制杀死退出了。

2.8docker top

docker top
功能

查看容器中运行的进程信息,支持 ps 命令参数
语法

bash 复制代码
docker top CONTAINER [ps OPTIONS]

别名

bash 复制代码
docker container top 

注意事项

容器运行时不一定有/bin/bash终端来交互执行top命令,而且容器还不一定有top 命令,可以使用docker top来实现查看container中正在运行的进程。

我们可以加上linux下的ps中的-aux选项看下效果:

bash 复制代码
knd@NightCode:~$ sudo docker top nginx1 
UID                 PID                 PPID                C                   STIME               TTY                 TIME                CMD
root                396322              396298              0                   17:39               ?                   00:00:00            nginx: master process nginx -g daemon off;

USER                PID                 %CPU                %MEM                VSZ                 RSS                 TTY                 STAT                START               TIME                COMMAND
root                396322              0.2                 0.2                 14788               8832                ?                   Ss                  17:39               0:00                nginx: master process nginx -g daemon off;

2.9docker stats

docker stats
功能

显示容器资源的使用情况,包括:CPU、内存、网络 I/O 等。
语法

bash 复制代码
docker stats [OPTIONS] [CONTAINER...] 

别名

bash 复制代码
docker container stats 

关键参数

  • --all , -a :显示所有的容器,包括未运行的。
  • --format :指定返回值的模板文件。如table,json
  • --no-stream :展示当前状态就直接退出了,不再实时更新。
  • --no-trunc :不截断输出。
    返回报文
  • CONTAINER ID 与 NAME: 容器 ID 与名称。
  • CPU % 与 MEM %: 容器使用的 CPU 和内存的百分比。
  • MEM USAGE / LIMIT: 容器正在使用的总内存,以及允许使用的内存总量。
  • NET I/O: 容器通过其网络接口发送和接收的数据量。
  • BLOCK I/O: 容器从主机上的块设备读取和写入的数据量。
  • PIDs: 容器创建的进程或线程数。

直接使用这个命令他会显示所有运行中的容器并阻塞窗口实时进行更新:

bash 复制代码
CONTAINER ID   NAME      CPU %     MEM USAGE / LIMIT    MEM %     NET I/O           BLOCK I/O   PIDS 
1129499f7390   nginx1    0.00%     4.77MiB / 3.636GiB   0.13%     2.82kB / 1.78kB   0B / 0B     5 

加上-a会把没有运行的容器状态也给显示出来,不过一般没啥用,他都不运行有什么查看的意义。

--format则是以指定格式输出,默认是table,还可以指定其他格式比如json:

bash 复制代码
knd@NightCode:~$ sudo docker stats --format json
{"BlockIO":"0B / 0B","CPUPerc":"0.00%","Container":"1129499f7390d7c1c476c056d66f0ca775da5977206abe6fcb811462a52d8ecb","ID":"1129499f7390","MemPerc":"0.13%","MemUsage":"4.809MiB / 3.636GiB","Name":"nginx1","NetIO":"3.23kB / 2.37kB","PIDs":"5"} 

如果只是想要当前运行容器的一个快照,则加上--no-stream 选项即可:

bash 复制代码
knd@NightCode:~$ sudo docker stats --no-stream
CONTAINER ID   NAME      CPU %     MEM USAGE / LIMIT     MEM %     NET I/O           BLOCK I/O   PIDS
1129499f7390   nginx1    0.00%     4.809MiB / 3.636GiB   0.13%     4.97kB / 2.85kB   0B / 0B     5
knd@NightCode:~$ 

2.10docker container inspect

docker container inspect
功能

查看容器详细信息
语法

bash 复制代码
docker container inspect [OPTIONS] CONTAINER [CONTAINER...] 

关键参数

  • -f :指定返回值的模板文件。如table、json
  • -s :显示总的文件大小。
    注意事项:
    docker inspect 会自动检查是镜像还是容器然后显示相信信息
bash 复制代码
knd@NightCode:~$ sudo docker inspect nginx1
[
    {
        "Id": "1129499f7390d7c1c476c056d66f0ca775da5977206abe6fcb811462a52d8ecb",
        "Created": "2025-12-22T07:02:02.181355153Z",
        "Path": "/docker-entrypoint.sh",
        "Args": [
...
knd@NightCode:~$ sudo docker inspect -f json nginx1
[{"Id":"1129499f7390d7c1c476c056d66f0ca775da5977206abe6fcb811462a52d8ecb","Created":"2025-12-22T07:02:02.181355153Z","Path":"/docker-entrypoint.sh","Args":["nginx","-g","daemon off;"],

加上-s可以看到文件大小相关内容:

bash 复制代码
knd@NightCode:~$ sudo docker inspect -s nginx1 | grep Size
            "ConsoleSize": [
            "ShmSize": 67108864,
        "SizeRw": 90112,
        "SizeRootFs": 165273600,

2.11docker port

docker port
功能

用于列出指定的容器的端口映射,或者查找将 PRIVATE_PORT NAT 到面向公众

的端口。
语法

bash 复制代码
docker port CONTAINER [PRIVATE_PORT[/PROTO]]

别名

bash 复制代码
docker container port

我们还是以nginx容器为例子,用它进行相关演示,比如我想看它映射了哪些端口可以直接指定其容器名:

bash 复制代码
knd@NightCode:~$ sudo docker port nginx1
80/tcp -> 0.0.0.0:8080
80/tcp -> [::]:8080

可以看到它映射的有一个端口且通信协议为tcp类型的。

还可以指定端口查看容器内此端口是否被映射到主机上实际的端口上,同时也可以指定端口使用的通信协议进行过滤:

bash 复制代码
knd@NightCode:~$ sudo docker port nginx1 8080
no public port '8080' published for nginx1
knd@NightCode:~$ sudo docker port nginx1 80
0.0.0.0:8080
[::]:8080
knd@NightCode:~$ sudo docker port nginx1 80/udp
no public port '80/udp' published for nginx1
knd@NightCode:~$ sudo docker port nginx1 80/tcp
0.0.0.0:8080
[::]:8080

2.12docker cp

docker cp
功能

在容器和宿主机之间拷贝文件
语法

bash 复制代码
docker cp [OPTIONS] CONTAINER:SRC_PATH DEST_PATH|-
docker cp [OPTIONS] SRC_PATH|- CONTAINER:DEST_PATH

别名

bash 复制代码
docker container cp

比如我想要将nginx1容器内的index.html首页文件拷到我当前主机的工作目录下,可以这样搞:

bash 复制代码
knd@NightCode:~/dockertest$ sudo docker cp  nginx1:/usr/share/nginx/html/index.html ./
Successfully copied 2.56kB to /home/knd/dockertest/./
knd@NightCode:~/dockertest$ ls
index.html  namespacets  nginx.tar

或者说我想要把我的index.html文件给拷贝到容器内的对应位置下,这里我把刚刚考下来的index.html改为前文我们用ai写的一个模拟b站的静态前端页面,然后给它拷回去:

bash 复制代码
knd@NightCode:~/dockertest$ sudo docker cp ./index.html nginx1:/usr/share/nginx/html/index.html
Successfully copied 17.9kB to nginx1:/usr/share/nginx/html/index.html

这时去访问容器内的nginx通过浏览器就会发现内容改变了:

2.13docker diff

docker diff
功能

检查容器里文件结构的更改。
语法

bash 复制代码
docker diff CONTAINER

这里刚好就可以看下我们前面修改了index.html是否有记录:

bash 复制代码
knd@NightCode:~/dockertest$ sudo docker diff nginx1
C /usr
C /usr/share
C /usr/share/nginx
C /usr/share/nginx/html
C /usr/share/nginx/html/index.html

C就是change的意思,A就是add的意思。说明我们刚刚的修改此处也被记录下来了。

2.14docker commit

docker commit
功能

从容器创建一个新的镜像。
语法

docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]
参数

  • -a :提交的镜像作者;
  • -c :使用 Dockerfile 指令来创建镜像;可以修改启动指令
  • -m :提交时的说明文字;
  • -p :在 commit 时,将容器暂停。

这个命令就很香了,你看如果我们在容器内做了某些自定义式的操作,比如比较流行的用astrbot部署一个社交平台机器人,如果我们想换个地方继续保存我们之前的配置运行,那就很舒服直接用docker commit给他打包成我们自己的镜像即可:

之前我们把nginx容器删除了之后再让他run起来会导致我们之前的文件丢了,比如我们上面的那个仿b站的html。我们这里用上面修改过的容器制作一个镜像然后让他跑起来访问它看看给我们的是什么内容(如果不指定标签就会出现untagged的情况):

bash 复制代码
knd@NightCode:~/dockertest$ sudo docker commit nginx1
sha256:e6e11f2794de7aba0676a44da8648009a589fe3a205f339c325efcb1facb648f
knd@NightCode:~/dockertest$ sudo docker images -a
                                                                                                                                                                                                                                                        i Info →   U  In Use
IMAGE          ID             DISK USAGE   CONTENT SIZE   EXTRA
nginx:1.29.4   fb01117203ff        228MB         62.6MB    U   
<untagged>     e6e11f2794de        225MB         59.8MB   
knd@NightCode:~/dockertest$ sudo docker tag e6e11f2794de nginx:v1.0
knd@NightCode:~/dockertest$ sudo docker images -a
                                                                                                                                                                                                                                                        i Info →   U  In Use
IMAGE          ID             DISK USAGE   CONTENT SIZE   EXTRA
nginx:1.29.4   fb01117203ff        228MB         62.6MB    U   
nginx:v1.0     e6e11f2794de        225MB         59.8MB  

此时我们把原来的nginx1容器停了并删除,用这个新的镜像去跑一个容器:

bash 复制代码
knd@NightCode:~/dockertest$ sudo docker run -d --name=mynginx -p 8080:80  nginx:v1.0
6fb49cf4dff1864ff6642e24c07ff02bd16ccb8a3ce877e96c80d7b11eeb48f0
knd@NightCode:~/dockertest$ sudo docker ps -a
CONTAINER ID   IMAGE        COMMAND                  CREATED         STATUS         PORTS                                     NAMES
6fb49cf4dff1   nginx:v1.0   "/docker-entrypoint...."   5 seconds ago   Up 4 seconds   0.0.0.0:8080->80/tcp, [::]:8080->80/tcp   mynginx
knd@NightCode:~/dockertest$ curl 127.0.0.1:8080
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>仿Bilibili首页 - 简单静态版</title>

可以看到我们之前的内容被保留下来了。不过这些选项有什么用呢,-p后面我们用pause时更好看些,我们试试其他三个选项:

bash 复制代码
knd@NightCode:~/dockertest$ sudo docker commit -a knd -m 114514 -c 'CMD ["bash","ls -l"]' affectionate_brattain
sha256:9a91a65943a97d21c3e1e95d672f193f0bc555256eaddca7ffc182f75a75e0dc
knd@NightCode:~/dockertest$ sudo docker tag 9a91a65943a9 nginx:v3.0
knd@NightCode:~/dockertest$ sudo docker inspect nginx:v3.0
[
    {
        "Architecture": "amd64",
        "Author": "knd",
        "Comment": "114514",
        "Config": {
            "Cmd": [
                "bash",
                "ls -l"
            ],
...
knd@NightCode:~/dockertest$ sudo docker inspect nginx:v1.0
[
    {
        "Architecture": "amd64",
        "Config": {
            "Cmd": [
                "nginx",
                "-g",
                "daemon off;"
            ],
...

可以看到-a是设置作者,-m是设置备注信息,而-c,不仅仅可以修改启动命令,还可以干别的事情比如设置环境变量,设置工作目录,设置入口点和命令,暴露端口和设置标签等等。这个我们后面会细说。这里就先不展示那么多了:

bash 复制代码
knd@NightCode:~/dockertest$ sudo docker run -d --name=nginx1 -p 8080:80  nginx:v3.0
263a8722bd519fa1c0342ad1a23a1aeac0582180329b31d3d39bc92edb65af1a
knd@NightCode:~/dockertest$ sudo docker ps -a
CONTAINER ID   IMAGE        COMMAND                  CREATED         STATUS                       PORTS     NAMES
263a8722bd51   nginx:v3.0   "/docker-entrypoint...."   4 seconds ago   Exited (127) 4 seconds ago             nginx1
knd@NightCode:~/dockertest$ sudo docker logs nginx1
bash: ls -l: No such file or directory

你看它这里启动就去运行bash ls -l了,而不是启动nginx。

2.15docker pause与docker unpause

docker pause
功能

暂停容器中所有的进程。
语法

bash 复制代码
docker pause CONTAINER [CONTAINER...]

别名

bash 复制代码
docker container pause

样例

bash 复制代码
docker pause mynginx

docker unpause
功能

恢复容器中所有暂停的进程。
语法

docker unpause CONTAINER [CONTAINER...]
别名

bash 复制代码
docker container unpause

这两个命令很简单,我们看个简单的样例就ok:

bash 复制代码
knd@NightCode:~/dockertest$ sudo docker ps
CONTAINER ID   IMAGE        COMMAND                  CREATED          STATUS          PORTS                                     NAMES
4b1cbd2fc70c   nginx:v2.0   "/docker-entrypoint...."   22 seconds ago   Up 21 seconds   0.0.0.0:8080->80/tcp, [::]:8080->80/tcp   nginx1
knd@NightCode:~/dockertest$ sudo docker pause nginx1
nginx1
knd@NightCode:~/dockertest$ sudo docker ps -a
CONTAINER ID   IMAGE        COMMAND                  CREATED          STATUS                   PORTS                                     NAMES
4b1cbd2fc70c   nginx:v2.0   "/docker-entrypoint...."   32 seconds ago   Up 32 seconds (Paused)   0.0.0.0:8080->80/tcp, [::]:8080->80/tcp   nginx1
knd@NightCode:~/dockertest$ sudo docker ps 
CONTAINER ID   IMAGE        COMMAND                  CREATED          STATUS                   PORTS                                     NAMES
4b1cbd2fc70c   nginx:v2.0   "/docker-entrypoint...."   36 seconds ago   Up 36 seconds (Paused)   0.0.0.0:8080->80/tcp, [::]:8080->80/tcp   nginx1
knd@NightCode:~/dockertest$ sudo docker unpause nginx1
nginx1
knd@NightCode:~/dockertest$ sudo docker ps
CONTAINER ID   IMAGE        COMMAND                  CREATED          STATUS          PORTS                                     NAMES
4b1cbd2fc70c   nginx:v2.0   "/docker-entrypoint...."   48 seconds ago   Up 47 seconds   0.0.0.0:8080->80/tcp, [::]:8080->80/tcp   nginx1

上面commit加上-p时就是在容器变为镜像的时候变为暂停状态,跟上面示例中pause之后的容器状态一样。

2.16docker rm

docker rm
功能

删除停止的容器
语法

bash 复制代码
docker rm [OPTIONS] CONTAINER [CONTAINER...]

别名

bash 复制代码
docker container rm

关键参数

  • -f :通过 SIGKILL 信号强制删除一个运行中的容器。

这个就不演示了哈,毕竟和image哪里的rmi差不多,有兴趣的读者可以自行进行尝试。

2.17docker import(镜像命令)与docker export(容器命令)

之前我们说镜像的时候不是没说它,是因为他要从这里来配合容器的docker export才好说。
docker import
功能

从归档文件中创建镜像。
语法

docker import [OPTIONS] file|URL|- [REPOSITORY[:TAG]]
别名

docker image import
关键参数

  • -c :应用 docker 指令创建镜像;
  • -m :提交时的说明文字;

docker export
功能

导出容器内容为 tar 文件
语法

docker export [OPTIONS] CONTAINER
别名

docker container export
关键参数

  • -o:写入到文件。

emm,我们先把pause那块运行中的那个容器给他export下把:

bash 复制代码
knd@NightCode:~/dockertest$ sudo docker ps
CONTAINER ID   IMAGE        COMMAND                  CREATED          STATUS          PORTS                                     NAMES
4b1cbd2fc70c   nginx:v2.0   "/docker-entrypoint...."   48 seconds ago   Up 47 seconds   0.0.0.0:8080->80/tcp, [::]:8080->80/tcp   nginx1
knd@NightCode:~/dockertest$ sudo docker export -o ./nginx_export.tar nginx1
knd@NightCode:~/dockertest$ ls
index.html  namespacets  nginx_export.tar

然后先打住,这里如果只是简单的再把这个tar包给import其实就没有什么介绍的必要了,我们看看这对命令与save和load的区别,所以我们再用save将这个容器对应的镜像给他打成tar包用save命令:

bash 复制代码
knd@NightCode:~/dockertest$ sudo docker save -o ./nginx_save.tar  nginx:v2.0
knd@NightCode:~/dockertest$ ls
index.html  namespacets  nginx_export.tar  nginx_save.tar

好,把他们上市!(不过在此之前先删除下原来的nginx:v2.0...)

bash 复制代码
knd@NightCode:~/dockertest$ sudo docker load -i ./nginx_save.tar
Loaded image: nginx:v2.0
knd@NightCode:~/dockertest$ sudo docker import ./nginx_export.tar nginx:v3.0
sha256:370bbfa69ea67f7ad0b3d1fe5c30cc18e8d62ab085c54510802f8177886a3a31
knd@NightCode:~/dockertest$ sudo docker images
                                                                                                                                                                                                                                                        i Info →   U  In Use
IMAGE          ID             DISK USAGE   CONTENT SIZE   EXTRA
nginx:1.29.4   fb01117203ff        228MB         62.6MB        
nginx:v2.0     9391133565a3        225MB         59.8MB        
nginx:v3.0     370bbfa69ea6        224MB         60.4MB  

我们发现nginx:v3.0比nginx:v2.0小了些,这是有原因的-因为它没有保存数据,我们用inspect看下:

bash 复制代码
knd@NightCode:~/dockertest$ sudo docker inspect nginx:v2.0
...
        "Config": {
            "ExposedPorts": {
                "80/tcp": {}
            },
            "Env": [
                "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
                "NGINX_VERSION=1.29.4",
                "NJS_VERSION=0.9.4",
                "NJS_RELEASE=1~trixie",
                "PKG_RELEASE=1~trixie",
                "DYNPKG_RELEASE=1~trixie"
            ],
...
knd@NightCode:~/dockertest$ sudo docker inspect nginx:v3.0
...
        "Config": {},
...

可以看到3.0的用import导入的镜像config直接什么都没有了,当然少的不止这些数据,其他地方我们对比下也是有少的。所以一般如果想要离线迁移的话,如果是要从当前容器来搞,不要使用export,可以先commit然后再save进行迁移是比较好的选择。

2.18docker wait

docker wait
功能

阻塞运行直到容器停止,然后打印出它的退出代码。
语法

bash 复制代码
docker wait CONTAINER [CONTAINER...]

别名

bash 复制代码
docker container wait

这里我们把正在跑的一个nginx容器在A终端wait下,然后在B终端给他暂停了看下:

bash 复制代码
#A
knd@NightCode:~/dockertest$ sudo docker wait nginx
0
knd@NightCode:~/dockertest$ sudo docker start nginx
nginx
knd@NightCode:~/dockertest$ sudo docker wait nginx
137
bash 复制代码
#B
knd@NightCode:~$ sudo docker stop nginx
nginx
knd@NightCode:~$ sudo docker kill nginx
nginx

0是正常退出的情况,137是我们强制杀死容器中所有进程让其退出的情况。

2.19docker rename

docker rename
功能

重命名容器
语法

bash 复制代码
docker rename CONTAINER NEW_NAME

别名

bash 复制代码
docker container rename

如果我们在让容器开始跑的时候没有命名字或运行时想改容器名字,就可以使用rename来进行修改。因为比较简单就不演示了。

2.20docker container prune

docker container prune
功能

删除所有停止 的容器
语法

bash 复制代码
docker container prune [OPTIONS]

关键参数

  • -f, --force:不提示是否进行确认

注意,docker凡是带prune的命令执行之前我们最好清楚自己在干什么,因为基本都是批量化的操作。需要特别谨慎。因为这个命令一运行就会把所有停止的容器全部删除,我就不演示了,大家可以找一个测试环境进行测试。

2.21docker update

docker update
功能

更新容器配置
语法

bash 复制代码
docker update [OPTIONS] CONTAINER [CONTAINER...]

别名

bash 复制代码
docker container update

关键参数

  • --cpus: cpu 数量
  • --cpuset-cpus :使用哪些 cpu
  • --memory :内存限制
  • --memory-swap:交换内存
  • --cpu-period :是用来指定容器对 CPU 的使用要在多长时间内做一次重新分配
  • --cpu-quota: 是用来指定在这个周期内,最多可以有多少时间用来跑这个容器

一般来说我们不用update命令,像这些配置什么的我们早在run的时候就应该配置好,要不合适了直接删除再重新run我感觉来的更快些。所以这个命令就不演示了,有兴趣的读者可以自行进行尝试。

这里还需要注意的一点是,此命令不支持windows容器,在docker官方的文档中也有写。

三.基础的容器操作案例

3.1批量进行容器的停止与启动

基于上面的命令这里我们进行一个扩展,毕竟一个服务很多时候是需要多个不同的容器配合运行才能正常运转的,比如我们前面做过的脚手架的服务端。最后使用docker进行部署时,除了我们自己写的几个子服务外,还有mysql,rabbitmq,redis,elasticsearch等等容器需要启动。

命令 解释
docker container ls -qf name=xxx 根据名称过滤得到容器编号
docker container ls --filter status=running 根据状态过滤容器信息
docker container ls -aq 静默获取全部容器 id
docker container ls --filter ancestor=xxx 过滤镜像名为 xxx 的容器信息
docker container ls --filter ancestor=xxx 过滤镜像 id 为 xxx 的容器信息
  • -a:表示打印所有的容器信息, 包括正在运行和已经退出的
  • -q: 表示只返回容器 ID
  • -f: 表示基于给的条件过滤 等价于 --filter 选项

首先我们先启动多个基于不同的nginx镜像的nginx容器:

bash 复制代码
knd@NightCode:~$ sudo docker ps -a
CONTAINER ID   IMAGE          COMMAND                  CREATED          STATUS                      PORTS     NAMES
73af948ed6e3   nginx:1.29.4   "/docker-entrypoint...."   5 seconds ago    Up 4 seconds                80/tcp    nginx5
e108409142de   nginx:1.29.4   "/docker-entrypoint...."   8 seconds ago    Up 7 seconds                80/tcp    nginx4
a440dbbe04dc   nginx:1.29.0   "/docker-entrypoint...."   14 seconds ago   Up 13 seconds               80/tcp    nginx3
79fd5d231761   nginx:1.29.0   "/docker-entrypoint...."   17 seconds ago   Up 16 seconds               80/tcp    nginx2
6f854a123918   nginx:1.29.0   "/docker-entrypoint...."   20 seconds ago   Up 19 seconds               80/tcp    nginx1
f29660e6b9d0   nginx:1.29.4   "/docker-entrypoint...."   21 hours ago     Exited (137) 21 hours ago             nginx

-q是只获取容器ID而我们可以通过容器ID对容器进行停止与启动,那么我们就可以把查到的所有容器ID喂给docker命令,就像mysql嵌套执行一样,这里我们先进行对所有运行中容器的停止操作:

bash 复制代码
knd@NightCode:~$ sudo docker stop $(sudo docker ps -aq --filter status=running)
73af948ed6e3
e108409142de
a440dbbe04dc
79fd5d231761
6f854a123918
knd@NightCode:~$ sudo docker ps -a
CONTAINER ID   IMAGE          COMMAND                  CREATED         STATUS                      PORTS     NAMES
73af948ed6e3   nginx:1.29.4   "/docker-entrypoint...."   4 minutes ago   Exited (0) 11 seconds ago             nginx5
e108409142de   nginx:1.29.4   "/docker-entrypoint...."   4 minutes ago   Exited (0) 11 seconds ago             nginx4
a440dbbe04dc   nginx:1.29.0   "/docker-entrypoint...."   4 minutes ago   Exited (0) 11 seconds ago             nginx3
79fd5d231761   nginx:1.29.0   "/docker-entrypoint...."   4 minutes ago   Exited (0) 11 seconds ago             nginx2
6f854a123918   nginx:1.29.0   "/docker-entrypoint...."   4 minutes ago   Exited (0) 11 seconds ago             nginx1
f29660e6b9d0   nginx:1.29.4   "/docker-entrypoint...."   21 hours ago    Exited (137) 21 hours ago             nginx

然后我们把基于nginx:1.29.4镜像的容器全部启动:

bash 复制代码
knd@NightCode:~$ sudo docker start $(sudo docker ps -aq --filter ancestor=nginx:1.29.4)
73af948ed6e3
e108409142de
f29660e6b9d0

接着将名为nginx1的容器进行启动:

bash 复制代码
knd@NightCode:~$ sudo docker start $(sudo docker ps -aqf name=nginx1)
6f854a123918

最后我们基于nginx:1.29.0的镜像号对基于其创建的所有容器进行启动:

bash 复制代码
knd@NightCode:~$ sudo docker start $(sudo docker ps -aqf ancestor=nginx:1.29.0)
a440dbbe04dc
79fd5d231761
6f854a123918

当然你已经启动过的他不会在进行启动,从启动时间即可看出。

3.2为容器设定自动重启

容器重启选项如下:
docker run --restart=no [容器名] :默认值不自动重启
docker run --restart=on-failure:3 [容器名] : on-failure 若容器的退出状态非 0,则docker 自动重启容器,还可以指定重启次数,若超过指定次数未能启动容器则放弃
docker run --restart=always [容器名] :always 容器退出时总是重启
docker run --restart=unless-stopped [容器名] unless-stopped 容器退出时总是重启,但不考虑 Docker 守护进程启动时就已经停止的容器

如果容器启动时没有设置--restart 参数,则通过下面命令进行更新:
docker update --restart=always [容器名]

我们这里以always为例子演示下,比如我以交互模式进入,然后exit退出:

bash 复制代码
knd@NightCode:~$ sudo docker run -it -p 8080:80 --name=nginx --restart=always nginx:1.29.4 bash
root@b1b8ebd011e0:/# exit
exit
knd@NightCode:~$ sudo docker ps -a
CONTAINER ID   IMAGE          COMMAND                  CREATED         STATUS         PORTS                                     NAMES
b1b8ebd011e0   nginx:1.29.4   "/docker-entrypoint...."   8 seconds ago   Up 3 seconds   0.0.0.0:8080->80/tcp, [::]:8080->80/tcp   nginx

可以看到如果没有设置的情况下,理应是立马退出的,但是我们退出后发现它立马又起来了,我们再用kill与stop命令试下:

bash 复制代码
knd@NightCode:~$ sudo docker start nginx
nginx
knd@NightCode:~$ sudo docker stop nginx
nginx
knd@NightCode:~$ sudo docker ps
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES

stop命令会使nginx即便设置了总是重启策略他也会退出,kill也是,可见重启策略如果是用户执行命令进行影响会被忽略。也就是说,重启策略只会响应容器自身出问题或任务执行完毕之后的退出情况。

3.3通过文件向容器批量导入环境变量

我们知道,如果run的时候需要向容器内添加容器变量时,若环境变量过多需要我们不断的去输入-e [环境变量:环境变量内容]。此时我们使用文件进行导入就舒服多了,也就是加上**--env-file**选项并指定文件的路径:

bash 复制代码
knd@NightCode:~/dockertest$ cat myenv.txt 
MYTEST1=1
MYTEST2=2
MYTEST3=3
MYTEST4=4
knd@NightCode:~/dockertest$ sudo docker run -d --name=nginx1 -p 8080:80 --env-file ./myenv.txt nginx:1.29.4
dea83f15d3c2ef4ed1478ae2e3defd93b71b15013ff87efcf8bd7ba19c6a4eda
knd@NightCode:~/dockertest$ sudo docker exec -it nginx1 env | grep MYTEST
MYTEST1=1
MYTEST2=2
MYTEST3=3
MYTEST4=4

可以看到环境变量已经被成功的批量导入。

3.4获取容器日志信息

有的时候我们容器部署在客户的机器上,如果程序出问题了而且我们又无法直接访问客户机器,就需要让客户将日志文件发送过来。我们有两种方式可以获取日志文件,第一种是直接访问容器的文件目录获取其所有日志的json文件:

bash 复制代码
root@NightCode:/var/lib/docker/containers/dea83f15d3c2ef4ed1478ae2e3defd93b71b15013ff87efcf8bd7ba19c6a4eda# cat dea83f15d3c2ef4ed1478ae2e3defd93b71b15013ff87efcf8bd7ba19c6a4eda-json.log 
{"log":"/docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration\n","stream":"stdout","time":"2025-12-24T10:52:22.884309326Z"}
{"log":"/docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/\n","stream":"stdout","time":"2025-12-24T10:52:22.884525692Z"}
{"log":"/docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh\n","stream":"stdout","time":"2025-12-24T10:52:22.88527518Z"}
...

第二种方式是将容器的日志以表格的方式保存到文件中,重定向logs命令的输出即可:

bash 复制代码
knd@NightCode:~/dockertest$ sudo docker logs nginx1 > nginx.log 2> err.log
#也可以这样写,就是把正常日志信息与异常日志信息分开获取保存到不同的文件中,1为stdout标准输出流,2为stderr标准错误输出流
#sudo docker logs nginx1 1> nginx.log 2> err.log
knd@NightCode:~/dockertest$ cat err.log 
2025/12/24 10:52:22 [notice] 1#1: using the "epoll" event method
2025/12/24 10:52:22 [notice] 1#1: nginx/1.29.4
2025/12/24 10:52:22 [notice] 1#1: built by gcc 14.2.0 (Debian 14.2.0-19) 
2025/12/24 10:52:22 [notice] 1#1: OS: Linux 6.8.0-71-generic
2025/12/24 10:52:22 [notice] 1#1: getrlimit(RLIMIT_NOFILE): 1024:524288
2025/12/24 10:52:22 [notice] 1#1: start worker processes
2025/12/24 10:52:22 [notice] 1#1: start worker process 29
2025/12/24 10:52:22 [notice] 1#1: start worker process 30
2025/12/24 10:52:22 [notice] 1#1: start worker process 31
2025/12/24 10:52:22 [notice] 1#1: start worker process 32
knd@NightCode:~/dockertest$ cat nginx.log 
/docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
/docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
/docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
10-listen-on-ipv6-by-default.sh: info: Getting the checksum of /etc/nginx/conf.d/default.conf
10-listen-on-ipv6-by-default.sh: info: Enabled listen on IPv6 in /etc/nginx/conf.d/default.conf
/docker-entrypoint.sh: Sourcing /docker-entrypoint.d/15-local-resolvers.envsh
/docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh
/docker-entrypoint.sh: Launching /docker-entrypoint.d/30-tune-worker-processes.sh
/docker-entrypoint.sh: Configuration complete; ready for start up

四.较为综合的容器操作案例

4.1使用docker进行mysql数据库的容器化部署

接下来远程访问我们都是用的是navicat进行远程访问,其免费版完全能够满足我们的学习需求。

首先我们需要到docker hub拉取一个mysql镜像下来,我们拉取一个8.0.44版本的:

bash 复制代码
sudo docker pull mysql:8.0.44

可以看到官方镜像下面提供了一个一键式启动的命令(我把密码改成了114514名称改成了mysql,以及版本改成了我们所使用的版本):

bash 复制代码
$ docker run --name mysql -e MYSQL_ROOT_PASSWORD=114514 -d mysql:8.0.44

我们用这个命令进行mysql容器的启动,同时配置映射端口便于我们后续访问:

bash 复制代码
knd@NightCode:~$ sudo docker run --name mysql -e MYSQL_ROOT_PASSWORD=114514 -d -p 8080:3306 mysql:8.0.44
31bda89743a49e3007f277dd35c94fa14c3da38a5b6a03ff75a796f8fe61b331

然后先进入下容器,看看本地是否能够正常访问数据库:

bash 复制代码
knd@NightCode:~$ sudo docker exec -it mysql bash
bash-5.1# ls
afs  bin  boot  dev  docker-entrypoint-initdb.d  entrypoint.sh  etc  home  lib  lib64  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var
bash-5.1# mysql -u root -p 
Enter password: 
Welcome to the MySQL monitor.
...

创建一个test_db数据库,然后创建一张学生表插入一条数据:

bash 复制代码
CREATE TABLE students (
id INT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
sn INT NOT NULL UNIQUE COMMENT '学号',
name VARCHAR(20) NOT NULL,
qq VARCHAR(20)
);
mysql> insert into students values(null,1,'tiansuohaoer',114514);
Query OK, 1 row affected (0.01 sec)

mysql> select * from students;
+----+----+--------------+--------+
| id | sn | name         | qq     |
+----+----+--------------+--------+
|  1 |  1 | tiansuohaoer | 114514 |
+----+----+--------------+--------+
1 row in set (0.00 sec)

接下来我们使用navicat远程访问查看下是否有对应数据:

可以看到访问成功并且能够看到我们刚刚添加的数据。

4.2使用docker进行redis的容器化部署

这里我们使用redis:8的版本进行部署:

bash 复制代码
sudo docker pull redis:8

根据官方给的一键式部署命令,我们可以自定义化如下:

bash 复制代码
$ sudo docker run --name redis -d -p 8080:6379 redis:8

进入容器,使用客户端工具本地访问redis:

bash 复制代码
root@c5da0edf5d38:/data# redis-cli           
127.0.0.1:6379> keys *
(empty array)
127.0.0.1:6379> set key1 "hello"
OK
127.0.0.1:6379> get key1
"hello"

然后使用navicat远程进行访问:

可以看到成功的远端进行访问并且查到了我们刚刚添加的缓存数据。

4.3制作一个C++程序镜像

这里我们拉取ubuntu24.04版本的镜像到本地并运行,然后进入镜像内部。首先配置下中科大的镜像加速:

bash 复制代码
sudo sed -i 's@//.*archive.ubuntu.com@//mirrors.ustc.edu.cn@g' /etc/apt/sources.list

当然你要是不想用这个系统,也可以参考中科大镜像源官网提供的其他系统镜像加速配置:

https://mirrors.ustc.edu.cn/help/index.html

我这里已经sudo apt update完毕了,接下来直接安装gcc即可:

bash 复制代码
sudo apt install build-essential

编写一个c++代码打印hello docker,然后使用gcc生成可执行程序,这样我们就可以基于这个容器给他打包成一个镜像了,我们可以看下基于此C++镜像制作的这个容器的运行效果:

bash 复制代码
knd@NightCode:~$ sudo docker exec -it ubuntu /data/app
hello docker

这里还需要补充下,其实这样子打包一个C++程序镜像是不对的,虽然最简单,但是镜像体积太大了,tar包都有443mb。显然不太合理。

一般在打包C++程序的Docker镜像时,为了在保证程序可靠运行的同时优化镜像体积 ,通常采用以下策略:

编译与运行环境分离的多阶段构建方法:

  • 构建阶段:使用包含完整开发工具链的基础镜像(如gcc:latest、ubuntu:latest)进行程序编译和链接
  • 依赖分析:通过工具(如ldd、objdump)静态分析程序依赖的共享库,同时考虑动态加载(dlopen)和隐式依赖(如配置文件、数据文件)
  • 运行阶段:选择与构建环境兼容的最小化基础镜像(如alpine、distroless、scratch),将编译好的二进制文件和精确识别的运行时依赖一起导入
  • 兼容性保证:通过静态链接关键库、设置运行时路径(rpath)或使用相同libc版本等方式确保环境兼容性

我们在打包之前的视频点播系统的服务端的镜像时就采取的这种策略。

TIPS:补充docker import 和 docker load 有什么区别

这个问题本质上问的是docker exportdocker save的区别。
docker save images_name:将一个镜像导出为文件,再使用 docker load 命令将文件导入为一个镜像,会保存该镜像的的所有历史记录。比 docker export 命令导出的文件大,很好理解,因为会保存镜像的所有历史记录。
docker export container_id:将一个容器导出为文件,再使用 dockerimport 命令将容器导入成为一个新的镜像,但是相比 docker save 命令,容器文件会丢失所有元数据和历史记录,仅保存容器当时的状态,相当于虚拟机快照。

既可以使用 docker load 命令来导入镜像库存储文件到本地镜像库,也可以使用docker import 命令来导入一个容器快照到本地镜像库。

两者的区别在于容器快照将会丢弃所有的历史记录和元数据信息,而镜像存储文件将保存完整记录,体积也会更大。

相关推荐
派大鑫wink2 小时前
【Day13】集合框架(一):List 接口(ArrayList vs LinkedList)实战
java·开发语言·windows
Filotimo_2 小时前
在java后端开发中,ES的用处
java·elasticsearch·jenkins
华仔啊2 小时前
都在用 Java8 或 Java17,那 Java9 到 16 呢?他们真的没用吗?
java·后端
WizLC2 小时前
【后端】面向对象编程是什么(附加几个通用小实例项目)
java·服务器·后端·python·设计语言
刘个Java2 小时前
手搓遥控器通过上云api执行航线
java·redis·spring cloud·docker
wanghowie2 小时前
01.09 Java基础篇|算法与数据结构实战
java·数据结构·算法
ComputerInBook2 小时前
C++ 标准提供的 thread (线程)之 join() 函数示例(windows平台)
c++·线程·join函数
HalvmånEver2 小时前
Linux:库制作与原理(四)
linux·运维·服务器
快乐的划水a2 小时前
嵌入式时间测量方法总结
c++·stm32·单片机