Docker 基础知识及常用命令

92 阅读10分钟

docker 基础知识

Docker 是一个开源的应用容器引擎。它允许开发者将应用及其所有依赖(如库、环境变量、配置文件等)打包到一个标准化的单元中,这个单元就称为容器

你可以把它想象成一个非常轻量级的虚拟机,但它不像虚拟机那样模拟整个操作系统,而是共享主机系统的内核,从而实现了极高的效率和资源利用率。

镜像是一个只读的模板快照。它包含了运行某个软件所需的一切:代码、运行时环境、系统工具、系统库和设置。

容器是镜像的一个运行时的实例。当你运行一个镜像时,Docker 会创建一个可写的容器层,你的应用就在这个隔离的环境中运行。一个镜像可以创建多个容器(就像一个类可以创建多个对象)

Docker 的强大并非来自某项单一的技术,而是巧妙地组合了 Linux 内核的几项关键技术,主要实现资源隔离资源限制

1. Namespaces(命名空间) - 实现隔离

命名空间负责提供隔离性,让每个容器觉得自己拥有一个独立的系统环境,看不到其他容器或主机上的进程。

  • PID Namespace:  隔离进程 ID。容器内的第一个进程 PID 为 1,它看不到主机上的其他进程。
  • Net Namespace:  隔离网络栈。每个容器有自己的网络设备(如 eth0)、IP 地址、端口和路由表。
  • Mount Namespace:  隔离文件系统挂载点。容器只能看到自己的文件系统视图。
  • UTS Namespace:  隔离主机名和域名。允许容器拥有自己的 hostname
  • IPC Namespace:  隔离进程间通信资源。
  • User Namespace:  隔离用户和用户组 ID。

2. Cgroups(Control Groups,控制组) - 实现资源限制

Cgroups 负责限制和记录一个进程组所使用的物理资源,防止某个容器耗尽主机上的所有资源。

  • 限制资源:  可以设置容器使用的CPU内存磁盘 I/O 等资源的上限。
  • 优先级:  可以设置资源使用的优先级。
  • 计量:  监控资源的实际使用情况。

3. Union File Systems(联合文件系统) - 实现镜像分层

UnionFS 是一种分层、轻量级并且高性能的文件系统。它支持将不同目录(称为层)的内容透明地叠加,形成一个单一连贯的文件系统视图。

  • Docker 镜像:  就是由一系列只读的 UnionFS 层组成的。
  • Docker 容器:  在启动时,会在镜像的所有只读层之上添加一个可写的空白层。所有对容器的修改(写操作)都会应用到这个可写层(这被称为“写时复制”,Copy-on-Write)。
  • 常见的驱动有:overlay2, aufs, devicemapper

4. 容器运行时(Container Runtime)

虽然 Docker 最初使用自己的 runc,但现在它遵循 OCI(开放容器倡议)  标准。其核心是一个低级别的运行时工具,负责与操作系统内核交互,直接创建和运行容器。

  • containerd:  是一个负责管理容器生命周期(pull镜像、创建、启动、停止容器)的守护进程。Docker Engine 通过 containerd 来操作容器。
  • runc:  是一个轻量级的命令行工具,它根据 OCI 规范来真正地创建和运行容器。containerd 会调用 runc 来执行具体任务。

 docker clientdocker daemoncontainerd 都是什么?

  • Docker Client (客户端) :就是你平时在命令行里打的 docker 命令(如 docker rundocker ps)。它的唯一工作就是告诉Docker守护进程该做什么。
  • Docker Daemon (守护进程 - dockerd :这是一个常驻在后台运行的进程。它是Docker的核心引擎,接收来自Client的命令,并负责高级功能,如构建镜像(docker build)、管理网络、管理数据卷等。它把关于容器生命周期(运行、停止)的具体操作都交给 containerd 去办。
  • containerd:也是一个常驻在后台的守护进程。它是一个更专注的容器运行时管理器,专门负责容器的生命周期操作——拉取镜像、创建、启动、停止、销毁容器。它被设计成可以被其他系统(比如Kubernetes)直接调用,而无需经过Docker Daemon。它在Docker生态中承上启下的作用

 runc 是什么?和 containerd 啥关系?

  • runc:它是一个极其简单、轻量级的命令行工具(不是守护进程)。它只做一件事——根据OCI标准(一个开放容器格式的规范)来创建和运行容器。它直接调用操作系统内核功能,是真正“创建”容器进程的那个点。
  • 关系containerd 是管理者,runc 是执行者containerd 为了完成“启动一个容器”这个任务,它会去启动一个 runc 进程,并告诉它:“去,用这个镜像,用这个配置,给我跑一个容器出来”。一个 containerd 可以管理无数个 runc 进程。

核心比喻:餐厅厨房

我们把整个Docker工作流程想象成一家餐厅的厨房:

  1. 你(用户) :顾客,来点菜。
  2. docker 命令(Docker Client) :服务员。你告诉服务员你想要什么(比如“一份清炒时蔬”)。
  3. Docker 守护进程(Docker Daemon - dockerd餐厅经理。服务员把订单交给经理。经理负责统筹全局,理解订单,但自己不亲自做菜。他决定需要哪些食材(镜像),并命令厨师长去执行。
  4. containerd厨师长。经理把任务派给厨师长。厨师长管理着所有厨房资源,负责整个做菜的流程:从仓库取食材、安排厨师干活、监督菜品制作过程。他同样不亲自切菜炒菜
  5. runc炒菜厨师。厨师长命令一个厨师去真正地开火、炒菜。这个厨师是真正动手干活的人,但他只负责执行这一个具体命令。
  6. 容器做好的那盘菜。是最终运行的实例。

流程回顾(点菜过程)
你(顾客)说:docker run nginx(服务员,来份nginx)
-> Docker Client(服务员)把命令告诉 Docker Daemon(经理)
-> Docker Daemon(经理)说:containerd(厨师长),我们需要运行一个nginx容器,你去搞定
-> containerd(厨师长)发现没有nginx镜像,就让手下(但通过经理)从仓库(Docker Hub)拉取镜像(取食材)。然后它命令 runc(炒菜厨师):你,用这个镜像当菜谱,给我做盘菜(启动容器)!
-> runc(炒菜厨师)调用Linux内核的各项技术(Namespace, Cgroups等)这个“厨房设备”,开始炒菜,最终把做好的菜(容器)端出来。

结论docker (Client) 是入口,dockerd (Daemon) 是大脑,containerd 是管家,runc 是干粗活的小工。

+-----------------------------------+
|   你敲的命令行: docker run ...     |  -> Docker Client
+-----------------------------------+
              | (通过REST API通信)
+-----------------------------------+
|        Docker Daemon (dockerd)    |  -> 大脑/经理 (管理镜像、网络、卷等)
+-----------------------------------+
              | (内部gRPC调用)
+-----------------------------------+
|           containerd              |  -> 管家/厨师长 (专注容器生命周期管理)
+-----------------------------------+
              | (遵守OCI规范调用)
+-----------------------------------+
|              runc                 |  -> 小工/厨师 (真正创建容器进程)
+-----------------------------------+
              | (调用Linux内核API)
+-----------------------------------+
|   Linux Kernel (Namespaces, etc.) |  -> 厨房设备
+-----------------------------------+

docker 镜像管理命令

  • docker pull 下载镜像

    功能:从 Docker 仓库下载镜像到本地

    完整的 docker pull 命令 由四个部分组成 [registry_address/][namespace/][image_name][:tag]

    docker pull docker.io/library/nignx:lates

    • registry_address 是Docker仓库的注册表地址。这里docker.io 是 Docker Hub官方仓库,可省略
    • namespace 是命名空间,通常是作者或者组织名称。这里的library 是 Docker官方仓库的命名空间,可省略
    • image_name 是镜像的名字
    • tag 是镜像的标签名,通常表示版本号,lastest 表示最新版本,可省略
  • docker images 列出本地镜像

    功能:列出本地镜像

    REPOSITORY   TAG       IMAGE ID       CREATED       SIZE                                                     
    redis        latest    f1285ef3611d   4 weeks ago   137MB                                                    
    nginx        latest    41f689c20910   5 weeks ago   192MB
    
  • docker rmi 删除镜像

    功能:删除本地镜像

    参数:指定镜像名称或ID

docker 容器管理命令

  • docker run 创建并运行容器

    功能:使用指定的镜像创建并运行一个容器,如果本地不存在指定镜像,docker 会自动拉取,再创建并运行

    docker run nginx

    /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                                            
    2025/09/21 07:59:46 [notice] 1#1: using the "epoll" event method                                             
    2025/09/21 07:59:46 [notice] 1#1: nginx/1.29.1                                                               
    2025/09/21 07:59:46 [notice] 1#1: built by gcc 12.2.0 (Debian 12.2.0-14+deb12u1)                             
    2025/09/21 07:59:46 [notice] 1#1: OS: Linux 5.15.0-153-generic                                               
    2025/09/21 07:59:46 [notice] 1#1: getrlimit(RLIMIT_NOFILE): 1048576:1048576                                  
    2025/09/21 07:59:46 [notice] 1#1: start worker processes                                                     
    2025/09/21 07:59:46 [notice] 1#1: start worker process 30                                                    
    2025/09/21 07:59:46 [notice] 1#1: start worker process 31 
    
    
    • -d (detached mode)

      功能:让容器在后台执行,不阻塞当前终端窗口

      docker run -d redis

       220f46accaa4513400c186ae8a132fe30a1a504810dfa4f5c5c60be7daeef9a9 
      
    • -p (port mapping/端口映射)

      docker 容器运行在独立的虚拟网络中,默认无法直接从宿主机访问内部网络

      功能:将宿主机的端口映射到容器内部的端口

      docker run -p 5000:6379 redis

      将宿主机的 5000 端口映射到 redis 容器内部 6379 端口

    • -v(volumemounting / 挂载卷)

      功能:将宿主机的文件目录与容器内部的文件目录进行绑定 目的:实现数据的持久化,当容器被删除时,容器内部的数据也会被删除,但挂载卷后可以把数据保存到宿主机上

      docker run -d -p 80:80 -v /website/html:/usr/share/nginx/html nginx

    • -e(环境变量)

      功能:向容器内部传递环境变量

      语法: -e <key>=<value>

    • --name(自定义容器名称)

      功能:为容器指定一个自定义的名称

      docker run --name my_redis redis

    • -it(interactive & tty / 交互式终端)

      docker run -it <镜像名称> /bin/bash (或 /bin/sh)

    • --rm (运行结束后自动删除)

      功能:当容器停止时,自动将其从宿主机删除

      docker run --rm redis

      常与 -it 组合使用,用于调试场景

    • --restart (重启策略)

      功能:配置容器停止时的行为 常用策略:

      • always:只要容器停止(包括内部错误、断电等),就会立即重启
      • unless-stopped:除非手动停止容器,否则都会尝试重启
  • 容器启动与管理

    • doker stop <容器id或名称>:停止一个正在运行的容器
    • docker start <容器id或名称>:重新启动一个已经停止的容器
    • docker inspect <容器id或名称>:查看容器的详细配置信息
    • docker create <镜像名称>:只创建容器,但不立即启动
    • docker rm <容器id或名称>:删除一个已经停止的镜像
      • -f 强制正在运行的容器
    • docker ps:查看正在运行的容器
      • -a 查看所有的容器,包括已经停止的
  • 容器内部操作与调试

    • docker logs <容器id或名称>:查看容器的运行日志

      • -f 滚动查看日志、实时刷新
    • docker exec 在容器内部执行命令

      功能:在一个正在运行的容器内部执行 Linux 命令

      docker exec my_nginx ps -ef 查看容器内部的进程

      进入交互式命令行环境:docker exec -it <容器id或名称> /bin/bash(或/bin/sh)