🐳 Docker核心知识与实践指南:从容器基础到镜像构建全解析

摘要:本文系统梳理了Docker的核心概念,深入剖析了镜像的分层结构与容器的运行机制,并提供了从基础命令到Dockerfile实战的完整操作手册。无论你是刚入门的新手,还是希望巩固基础的开发者,都能从中获得清晰的认知与实用的技能。


一、容器与镜像:Docker的基石

在深入实践之前,我们必须先厘清Docker最核心的两个概念:镜像(Image)**与**容器(Container)。

1. 什么是容器(Container)?
容器是镜像运行时的实例。你可以把它理解为一个轻量级的、独立的、可执行的软件包,它包含了运行某个应用所需的一切:代码、运行时环境、库、环境变量和配置文件。

  • 轻量级:基于镜像启动,秒级即可完成。
  • 隔离性:通过Linux的命名空间(Namespace)和控制组(cgroups)技术,实现进程、网络、文件系统的隔离,互不影响。
  • 可移植:在任何支持Docker的环境中,容器都能保证一致的运行效果。

2. 什么是镜像(Image)?
镜像是一个只读的模板,它是创建容器的基石。一个镜像可以包含一个完整的操作系统环境,预装了Nginx或其他用户添加的应用程序。

  • 分层结构:镜像由多个只读层(Read-only Layers)叠加而成,这是其高效的核心。
  • 不可变性:镜像一旦创建,其内容就不会改变,这确保了环境的一致性。
  • 可分发:镜像可以被推送到仓库(如Docker Hub)进行共享和分发。

3. 容器与镜像的关系
为了更直观地理解,我们可以通过一个表格来对比:

维度镜像 (Image)容器 (Container)
面向对象类比类 (Class)对象/实例 (Instance)
操作系统类比程序 / 安装包 (如.iso)进程 (Process)
生活类比菜谱 / 房屋设计蓝图按照菜谱做出的菜 / 建好的房子
本质属性静态的、只读的模板动态的、可读写的运行实体
生命周期持久化存在(除非手动删除)临时存在(随进程启停而创建/销毁)

一句话总结:镜像是容器的基础模板,定义了运行环境;容器是镜像的运行实例,是真正执行业务逻辑的载体。一个镜像可以同时启动多个完全隔离的容器。


二、深入理解:镜像的分层结构与容器的可写层

这是Docker最精妙的设计之一,理解它对于优化镜像和排查问题至关重要。

1. 镜像的分层结构(只读层)
镜像并非一个单一的大文件,而是由多个只读层叠加而成。

  • 指令即层:Dockerfile中的每一条指令(如FROM, RUN, COPY)都会创建一个新的镜像层。
  • 资源复用:这种设计极大地提升了效率。例如,10个基于nginx:alpine的镜像,在宿主机上只需存储一份基础层,节省了巨大的磁盘空间和网络带宽。

2. 容器的可写层(Container Layer)
当你执行docker run启动一个容器时,Docker会在所有镜像只读层的顶部,添加一个薄薄的可写层。

  • 读取文件:当容器内的程序需要读取一个文件时,Docker会通过联合文件系统从上到下查找并返回。
  • 写入文件(Copy-on-Write机制):当容器需要修改一个已存在于只读层的文件时,Docker会先将该文件“复制”到顶部的可写层,然后在可写层中进行修改。

核心结论:容器内的所有修改(增、删、改)都只发生在最顶部的可写层中,绝对不会影响底层的原始镜像。这也解释了为什么容器的生命周期是临时的,一旦容器被删除,其可写层也随之消失。


三、Docker容器管理常用命令速查

掌握以下命令,你就掌握了Docker日常操作的核心。

操作分类命令示例说明
帮助docker --help获取Docker命令帮助
镜像下载docker pull centos下载CentOS镜像
镜像打包docker save -o centos.tar centos:7将本地镜像打包为tar文件
镜像导入docker load -i centos.tar将tar包导入为本地镜像
启动容器docker run -it --name=c1 centos:latest /bin/bash启动一个交互式容器
挂起容器Ctrl+P+Q在容器内按下组合键,挂起容器(Detach)
停止容器docker stop <容器ID/名称>停止运行中的容器
启动容器docker start <容器ID/名称>启动已停止的容器
进入容器docker attach <容器ID/名称>重新连接到正在运行的容器
容器导出docker export -o centos-httpd.tar c1基于现有容器打包为tar文件
导入镜像docker import centos-httpd.tar centos-httpd:v1基于容器导出文件生成新镜像
删除容器docker rm c1删除已停止的容器
端口映射docker run -it -p 8081:80 --name c100 centos-httpd:v1 /bin/bash将宿主机8081端口映射到容器80端口
数据卷挂载docker run -it -v /share:/data --name c10 centos:7将宿主机目录挂载到容器,实现数据持久化
时间同步docker run -it -v /etc/localtime:/etc/localtime centos:7 /bin/bash同步容器与宿主机时间
外部执行docker exec <容器ID/名称> <命令>在容器外执行容器内的命令
容器互联docker run --link c100:mysql -it --name c200 centos:7 /bin/bash建立容器间的连接

查看容器IP地址的三种方法:

  1. 进入容器查看:

    docker run -it --name=c1 centos:7 /bin/bash
    yum install -y iproute net-tools
    ip a # 或 ifconfig
    
  2. 在Docker Host查看:

    docker inspect c1
    
  3. 在Docker Host执行容器命令:

    docker exec c1 ifconfig
    

四、实战:两种制作应用镜像的方法

制作自己的应用镜像是Docker的核心技能,主要有两种方式。

方法一:使用 docker commit 提交镜像
这种方法类似于给虚拟机拍快照,将容器的当前状态保存为新镜像。

  1. 启动基础镜像并安装服务

    # 启动基础镜像
    docker run -it --name c1 centos:7 /bin/bash
    
    # 在容器内执行以下操作
    # 1. 备份并更换yum源(以阿里云vault源为例,解决CentOS 7源失效问题)
    mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.bak
    cat > /etc/yum.repos.d/CentOS-Base.repo << 'EOF'
    [base]
    name=CentOS-7-Vault-Base
    baseurl=https://mirrors.aliyun.com/centos-vault/7.9.2009/os/x86_64/
    gpgcheck=0
    enabled=1
    [updates]
    name=CentOS-7-Vault-Updates
    baseurl=https://mirrors.aliyun.com/centos-vault/7.9.2009/updates/x86_64/
    gpgcheck=0
    enabled=1
    [extras]
    name=CentOS-7-Vault-Extras
    baseurl=https://mirrors.aliyun.com/centos-vault/7.9.2009/extras/x86_64/
    gpgcheck=0
    enabled=1
    EOF
    
    # 2. 清理并重建缓存
    yum clean all && yum makecache
    
    # 3. 安装httpd服务
    yum -y install httpd
    echo "test httpd" > /var/www/html/index.html
    
  2. 提交为新镜像

    # 退出容器后,在宿主机执行
    docker commit c1 centos-httpd:v1
    
  3. 测试应用镜像

    docker run -it --name c2 centos-httpd:v1 /bin/bash
    # 在容器内启动服务并测试
    httpd -k start
    curl http://127.0.0.1
    

方法二:使用 Dockerfile 创建应用镜像(推荐)
Dockerfile是一个文本文件,包含了构建镜像所需的所有指令。这是更标准、更可重复、更易于维护的方式。

Dockerfile 核心关键字解析:

关键字说明
FROM指定基础镜像
MAINTAINER指定镜像创建者信息
RUN运行命令(构建阶段执行)
CMD设置容器启动时执行的操作
EXPOSE指定容器需要映射到宿主机的端口
ENV用于设置环境变量
ADD把Docker Host的文件复制到容器中
VOLUME指定挂载点
WORKDIR切换目录

五、Dockerfile 实战案例

案例1:创建启动即运行httpd应用的镜像

  1. 准备工作

    mkdir /test && cd /test/
    
  2. 创建启动脚本 run-httpd.sh

    #!/bin/bash
    /usr/sbin/httpd -D FOREGROUND
    
  3. 创建测试网页 index.html

    test httpd service!!!
    
  4. 编写 Dockerfile

    FROM centos:7
    MAINTAINER "wenteacher@163.com"
    RUN yum clean all
    RUN yum -y install httpd
    ADD run-httpd.sh /run-httpd.sh
    RUN chmod -v +x /run-httpd.sh
    ADD index.html /var/www/html/
    EXPOSE 80
    WORKDIR /
    CMD ["/bin/bash", "/run-httpd.sh"]
    
  5. 构建并测试镜像

    # 创建镜像
    docker build -t centos-httpd:v1 .
    
    # 测试镜像
    docker run -d --name c2 centos-httpd:v1
    curl http://<容器IP地址>
    

案例2:创建一个启动即运行Nginx应用的镜像

  1. 准备工作

    mkdir nginxtest && cd nginxtest/
    echo 'nginx is running!!!' > index.html
    
  2. 编写 Dockerfile

    FROM centos:7
    MAINTAINER "wenteacher@163.com"
    RUN yum clean all && \
        curl -o /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-7.repo && \
        yum -y install epel-release
    RUN yum -y install nginx
    ADD index.html /usr/share/nginx/html/
    RUN echo "daemon off;" >> /etc/nginx/nginx.conf
    EXPOSE 80
    CMD /usr/sbin/nginx
    
  3. 制作并测试镜像

    # 制作nginx应用镜像
    docker build -t centos-nginx:v1 .
    
    # 测试镜像(后台运行)
    docker run -d centos-nginx:v1
    

六、底层揭秘:容器镜像在Docker Host的存储位置

了解Docker在宿主机上的存储机制,有助于我们更好地理解其工作原理。

1. 存储位置与文件系统
Docker的容器镜像和容器数据都存放在服务器的/var/lib/docker/路径下。

  • Ubuntu 发行版:默认存储方式为 AUFS。
  • CentOS 发行版:默认存储方式为 Overlay 或 Overlay2。

OverlayFS简介:
它是一个现代联合文件系统,将单个Linux主机上的两个目录合并成一个目录(联合挂载)。

  • lowerdir:只读层,对应 Image层。
  • upperdir:可写层,对应 Container层。
  • merged:合并后的统一视图,对应我们看到的 Container。

2. /var/lib/docker/overlay2 目录的四个阶段变化

阶段描述/var/lib/docker/overlay2 状态
阶段一Docker运行前无docker相关目录
阶段二启动Docker后创建overlay2等目录,但overlay2为空
阶段三下载镜像后出现多个目录,存储镜像的只读层(lowerdir)
阶段四运行容器后在原有基础上,新增目录存储容器的可写层(upperdir)

更多推荐