Docker 容器实战 1—— docker 基础与镜像构建

1 Docker 简介

Docker 是一套开源的容器化虚拟化引擎,基于 Linux 内核能力实现应用隔离与打包。

传统虚拟机 KVM 是完整虚拟化 CPU、内存、磁盘,拥有独立操作系统内核;Docker 容器不虚拟化硬件,直接复用宿主机 Linux 内核,仅对应用进程做资源隔离

底层依赖三大 Linux 内核技术:

  1. Namespace:做隔离,隔离 PID 进程、网络、挂载、用户,容器内部看见一套独立的进程、网卡、文件系统视图。
  2. Cgroups:做资源限制,限制容器最多占用多少 CPU、内存、磁盘 IO,防止单个容器耗尽宿主机资源。
  3. UnionFS 联合文件系统:实现镜像分层存储,镜像可以多层叠加,修改容器只新增读写层,不改动底层只读镜像,节省存储空间。

四大核心概念:

  1. 镜像 Image
    镜像属于只读模板,存放应用程序、运行依赖、配置文件、环境变量。例如 mysql:5.7 镜像,相当于预制好的软件包,镜像本身不能运行。
  2. 容器 Container
    容器是镜像运行后的实例。在镜像只读层之上新增一层可读写层。同一个镜像,可以启动无数个独立容器。容器销毁时,读写层数据默认丢失,需要数据卷持久化保存数据。
  3. Dockerfile
    文本构建脚本,一系列指令,定义如何一步步构建镜像。写好 Dockerfile 后执行docker build生成自定义镜像。
    理解:基于已有镜像模板,通过 Dockerfile+build 制作出新镜像,再 run 这个新镜像跑容器。
  4. 仓库 Registry
    存放镜像的服务器,公共仓库 Docker Hub,企业内部搭建私有镜像仓库,用来上传、下载镜像。

核心优势

  1. 轻量:共享宿主机内核,不需要整套操作系统,占用磁盘、内存远小于 KVM 虚拟机。
  2. 启动快:进程级启动,秒级拉起业务;虚拟机需要启动完整操作系统,耗时分钟级别。
  3. 环境一致性:一次打包镜像,开发、测试、生产环境完全一致,解决 "本地能跑,线上跑不起来" 环境问题。
  4. 资源利用率高:一台物理机可以部署成百上千容器;虚拟机数量受硬件资源限制。
  5. 版本管理:镜像分层,支持版本回滚,分发拷贝便捷。

局限性

  1. 内核共享:容器直接使用宿主机内核,Windows 不能直接跑 Linux 容器;Linux 容器不能运行不同版本内核。
  2. 隔离弱于虚拟机:进程级隔离,不是硬件级隔离,对安全隔离等级要求极高的业务,优先选用 KVM 虚拟机。
  3. 不适合长时间运行传统大型数据库(MySQL 等建议做好数据卷持久化配置)。

2 Docker 架构

  1. Docker Engine(dockerd):Docker 守护进程。
  • 接收docker run / build / pull等客户端命令;处理镜像管理、网络、存储;对外提供 API。
  • 不再直接操作容器 ,把容器生命周期任务交给下层containerd
  1. containerd:容器管理守护进程,工业级容器管理器,K8s 也默认使用 containerd。
  • 接收 dockerd 下发指令,负责:容器生命周期管理、镜像解压、存储管理。
  • 每启动一个容器,就生成一个containerd‑shim
  1. containerd‑shim(垫片):每个容器对应独立的 shim 进程。
  • 充当 containerd 和 runC 中间垫片;
  • 保证即使 containerd 进程挂掉,容器还可以继续运行
  • 接管容器标准输入输出、日志,转发给上层。
  1. runC:OCI 容器运行时规范 的参考实现,是真正直接调用 Linux 内核接口,完成容器创建的工具。
    OCI(Open Container Initiative,开放容器倡议),是一套行业统一标准。主要定义两套规范:镜像规范 (容器镜像该长什么样、如何分层存储)和 运行时规范(如何调用内核 API 去启动一个容器)。
  • containerd‑shim 调用 runC,runC 去调用 Linux 系统调用,创建 Namespace、Cgroups,生成容器进程。
  • 容器创建完成后 runC 就退出,容器业务进程由 shim 托管。
  1. Linux Kernel(Linux 内核层)

    真正实现隔离、资源限制、安全管控,图中三个组件:

  2. namespaces:PID、NET、MNT 等,做隔离,制造独立视图。

  3. cgroups:CPU、内存、IO 资源限制,防止容器资源滥用。

  4. SELinux/AppArmor:内核安全模块,强制访问控制,加固容器安全。

完整调用流程:执行docker run

  1. 用户执行docker run → 发送请求到 Docker Engine(dockerd)
  2. dockerd 处理镜像、网络,把 "创建容器" 任务下发给 containerd
  3. containerd 为该容器启动 containerd‑shim 垫片进程
  4. shim 调用 runC
  5. runC 调用 Linux 系统调用,创建 Namespace、Cgroups,拉起容器 APP 进程
  6. 容器运行,shim 持续监控容器状态、转发日志;runC 任务完成退出

架构特点:就算上层dockerdcontainerd重启,只要containerd‑shim还在,容器业务进程不会停止。

3 Docker 部署

配置软件源、安装软件并启动服务

bash 复制代码
[root@docker1 ~]# cd /etc/yum.repos.d/
[root@docker1 yum.repos.d]# wget https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
[root@docker1 yum.repos.d]# yum install -y docker-ce
[root@docker1 yum.repos.d]# systemctl enable --now docker

查看 Docker 守护进程 (dockerd) 全局信息

复制代码
[root@docker1 yum.repos.d]# docker info

如果此处有警告,需激活以下内核选项

bash 复制代码
[root@docker1 ~]# sysctl -a|grep iptable
[root@docker1 ~]# sysctl -a|grep ip6table
[root@docker1 ~]# sysctl -a|grep ip_forward

把内核参数追加写入 docker 专属 sysctl 配置文件,此文件本身没有,是手动创建的。执行 sysctl --system,会按顺序扫描下面 4 个目录,加载目录下全部 *.conf 文件:

  1. /usr/lib/sysctl.d/*.conf
  2. /run/sysctl.d/*.conf
  3. /etc/sysctl.d/*.conf
  4. /etc/sysctl.conf
bash 复制代码
[root@docker1 ~]# echo "net.bridge.bridge-nf-call-iptables = 1" >> /etc/sysctl.d/docker.conf
[root@docker1 ~]# echo "net.bridge.bridge-nf-call-ip6tables = 1" >> /etc/sysctl.d/docker.conf
[root@docker1 ~]# echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.d/docker.conf
[root@docker1 ~]# sysctl --system
# 从系统全部配置文件加载生效内核参数,一次性读取所有 sysctl 配置文件并应用

查看IP,docker0是 Docker默认网桥(bridge)虚拟网卡 ,这个 IP 是 dockerd 守护进程自动生成分配的

安装网桥工具,查看 Linux 网桥信息

bash 复制代码
[root@docker1 ~]# yum install -y bridge-utils
[root@docker1 ~]# brctl show

4 Docker 基本操作

查看正在运行的容器,为空

bash 复制代码
[root@docker1 ~]# docker ps

搜索仓库镜像

bash 复制代码
[root@docker1 ~]# docker search docker.1ms.run/yakexi007

从仓库拉取镜像

bash 复制代码
[root@docker1 ~]# docker pull docker.1ms.run/yakexi007/mario
[root@docker1 ~]# docker images
# 查看本地镜像列表
[root@docker1 ~]# docker tag docker.1ms.run/yakexi007/mario:latest mario:latest
# 给本地镜像打新标签,相当于镜像别名
[root@docker1 ~]# docker rmi docker.1ms.run/yakexi007/mario:latest
# # 删除原有长路径标签

查看镜像的构建历史,逐层展示镜像每一层的创建信息,镜像内部 Dockerfile 写的 EXPOSE 8080,告诉使用者:这个容器服务默认监听 8080 端口

bash 复制代码
[root@docker1 ~]# docker history mario:latest

后台启动容器,指定容器名 demo,端口映射:宿主机80:容器8080

bash 复制代码
[root@docker1 ~]# docker run -d --name demo -p 80:8080 mario
[root@docker1 ~]# docker ps

访问IP

5 部署应用堆栈

堆栈(Stack):一组关联在一起,协同工作的多个服务 / 容器的集合。

举例子:

一个网站业务:Nginx(前端) + SpringBoot(后端) + MySQL(数据库) + Redis(缓存)

这 4 个容器配合才能跑完整业务,这一整套就叫应用堆栈

部署由 httpd + mysql 组成的简易业务堆栈,访问业务接口获取数据库用户列表

bash 复制代码
[root@docker1 ~]# docker stop demo
# 停止运行的 demo 容器
[root@docker1 ~]# ls
anaconda-ks.cfg  httpd.tar  mysql.tar  os.sql
# 从本地上传镜像包
[root@docker1 ~]# docker load -i httpd.tar
[root@docker1 ~]# docker load -i mysql.tar
# 导入上述两个镜像

查看镜像

bash 复制代码
[root@docker1 ~]# docker images

启动mysql容器,作为堆栈的数据库服务

bash 复制代码
[root@docker1 ~]# docker run -d -p 3306:3306 -e MYSQL_ROOT_PASSWORD=redhat --name dbserver mysql
[root@docker1 ~]# docker ps

查看dbserver容器日志

bash 复制代码
[root@docker1 ~]# docker logs dbserver

宿主机安装mariadb,提供mysql客户端命令,登录验证

bash 复制代码
[root@docker1 ~]# yum install -y mariadb
[root@docker1 ~]# mysql -h 127.0.0.1 -predhat

将本地os.sql脚本导入到容器内的mysql数据库,登录验证,导入成功

bash 复制代码
[root@docker1 ~]# mysql -h 127.0.0.1 -predhat < os.sql
[root@docker1 ~]# mysql -h 127.0.0.1 -predhat

启动httpd容器,使用--link关联数据库容器dbserver

bash 复制代码
[root@docker1 ~]# docker run -d -p 80:80 --link dbserver:db --name webserver httpd:webapp
[root@docker1 ~]# docker ps

进入webserver容器内部,查看action脚本源码,action脚本就是浏览器访问cgi‑bin/action调用的业务程序,该脚本会去连接数据库读取用户列表并输出网页

bash 复制代码
[root@docker1 ~]# docker exec -it webserver bash
[root@2e55ee5bf3ab /]# cd /var/www/cgi-bin/
[root@2e55ee5bf3ab cgi-bin]# ls
action  hostname
[root@2e55ee5bf3ab cgi-bin]# cat action

访问前端,可以看到数据库里的内容

6 镜像构建

6.1 镜像层

Docker 镜像由多层只读文件系统堆叠而成。每一层只记录这一层发生的文件变更(新增、修改、删除标记),不是完整操作系统。

  • 镜像层只读,构建完成后不能修改;要改内容只能往上叠加新层。
  • 容器启动时,会在所有只读镜像层之上自动生成一层容器读写层。容器内所有增删改操作全部发生在读写层,不会改动底层镜像层;容器删除,读写层连同内部改动全部销毁,镜像层不受影响。
  • 写时复制 CoW(Copy‑on‑Write):修改下层镜像层已存在的文件,会把文件复制到上层读写层再修改。

镜像常用子命令

命令(简写) 完整命令 作用
docker images docker image ls 列出本地所有镜像
docker build -t 名字:标签 . docker image build 构建镜像(Dockerfile 生成镜像)
docker rmi 镜像id/镜像名:tag docker image rm rmi = remove image,只删除标签;只有这个镜像没有其他标签时,才真正删除镜像层数据
docker tag 旧镜像:旧tag 新镜像:新tag docker image tag 给镜像打新标签(别名)
docker inspect 镜像id docker image inspect 查看镜像详细元数据(层、CMD、ENV 等)
docker pull 镜像名 docker image pull 从镜像仓库拉取镜像到本地
docker push 镜像名 docker image push 推送镜像到镜像仓库
docker save -o xxx.tar 镜像名:tag docker image save 把镜像导出为 tar 压缩包(离线迁移)
docker load -i xxx.tar docker image load 从 tar 包导入镜像

查看镜像层历史的命令,每一行代表一层镜像层

bash 复制代码
[root@docker1 docker]# docker history mysql:latest
  1. IMAGE:镜像层 ID,<missing>代表本地没有缓存这一层(多阶段构建 / 导入镜像经常出现)
  2. CREATED BY:生成这一层对应的 Dockerfile 指令,截图能看到:EXPOSE 8080/tcpWORKDIRCOPYRUN apt‑get installCMD
  3. SIZE:该镜像层占用大小

默认 docker history mario:latest 会把长命令截断,如上图中的省略号。

加参数--no-trunc:no truncate,不截断输出,完整展示每一层 CREATED BY 的原始命令

6.2 两种构建方式

镜像构建有两种方式:

  1. docker commit容器提交构建(手工构建)
  • 流程:run 启动容器 → 在容器里面手动改环境、创建文件、装软件 → commit 把当前容器磁盘状态打包成新镜像
  • 原理:抓取容器读写层全部变更 ,整体打包生成1 个全新的只读镜像层,追加到底层基础镜像之上
  • 缺点:所有修改全部压进同一层,无法拆分步骤,docker history看不到具体做了哪些操作
  1. docker build + DockerfileDockerfile 文件构建(自动化构建)
    写 Dockerfile,把每一步操作写成指令 RUN / COPY / ADD / EXPOSE ...
  • 原理:Dockerfile每一条可执行指令(RUN、COPY、ADD)都会生成独立的只读镜像层,一层层向上堆叠。
  • 缓存机制:构建会复用旧镜像层缓存;某一条指令改动,该指令及后续全部层重新构建,前面不变层直接复用。
  • 查看分层历史:docker history demo:v1,可以看到每一层对应的 Dockerfile 指令

Dockerfile 常用核心指令

指令 作用 说明
FROM xxx:tag as 别名 指定基础镜像 必须第一行,所有镜像都要基于一个父镜像;as build给阶段起别名,供COPY --from=引用
RUN 命令 构建阶段执行命令 构建镜像的时候运行,生成镜像层;不要用来启动容器程序
COPY src dest 复制文件到镜像 把宿主机上下文的文件拷贝进镜像内部
ADD src dest 复制 + 解压 比 COPY 多自动解压 tar 压缩包,普通文件优先用 COPY
EXPOSE 80 声明暴露端口 仅文档说明,不会自动做端口映射,run 的时候才 - p 映射
CMD "程序","参数" 容器启动默认命令 容器 run 起来之后执行,只会最后一条生效
ENTRYPOINT 容器入口程序 和 CMD 配合,固定启动命令,追加参数
WORKDIR /path 设置工作目录 后续 RUN/COPY 等指令默认工作目录,不存在自动创建
CMD "程序","参数" 容器启动默认命令 容器 run 起来之后执行,仅最后一条生效 ;可被docker run后面命令覆盖;容器 PID1 进程由此产生

解释:CMD

容器 run 起来之后执行,仅最后一条生效 ;可被docker run后面命令覆盖;容器 PID1 进程由此产生

例:在Dockerfile 里写

CMD ["/usr/local/nginx/sbin/nginx","-g","daemon off;"]

正常情况下启动容器:docker run -d --name web3 webserver:v3

容器就执行:nginx -g daemon off

若后面追加指令如 bash

docker run -it webserver:v3 bash

此时不再执行 nginx,转而执行bash,把 Dockerfile 的 CMD 直接作废

  1. 正常情况:不覆盖 CMD
    PID1 = /usr/local/nginx/sbin/nginx(nginx 作为一号进程)
  • nginx 前台运行,容器存活;
  • docker logs 可以捕获 nginx 的 stdout 标准输出日志;
  • nginx 停止 → PID1 消失 → 容器直接退出停止
  1. run 后面写 bash,覆盖 CMD
    PID1 = bash
  • nginx 要手动在容器内部敲命令启动,只是普通后台子进程;
  • docker logs 拿不到 nginx 日志;
  • 退出 bash,PID1 结束,容器立刻停止。

6.2.1 docker commit

把容器可写层(新增 file1/file2/file3、os.sql)做成一个新镜像层,叠加原来 busybox 底层只读镜像

bash 复制代码
[root@docker1 ~]# docker run -it --name demo docker.1ms.run/busybox
# 启动交互式容器
/ # touch file1 file2 file3
# 容器内,创建3个空文件
/ # [root@docker1 ~]# docker ps
ctrl+pq 退出容器,后台继续运行
[root@docker1 ~]# docker cp os.sql demo:/
# 宿主机文件拷贝到容器demo的根目录

attach 接入容器终端,查看,已经有file1‑3、os.sql

bash 复制代码
[root@docker1 ~]# docker attach demo
ctrl+d 退出容器

把停止的 demo 容器,提交保存为新镜像 demo:v1

bash 复制代码
[root@docker1 ~]# docker commit -m "add os.sql" demo demo:v1
# `docker commit`:把容器当前可写层的改动,打包生成全新镜像
# -m "add os.sql" 添加注释说明

查看生成的镜像及镜像分层历史

bash 复制代码
[root@docker1 ~]# docker images demo:v1
[root@docker1 ~]# docker history demo:v1
  1. 第一层(最新):sh,大小 1.58MB,注释add os.sql,这就是 commit 新增的镜像层,包含我们新建的 3 个文件 + 拷贝进去的 os.sql。
  2. 底层:原始 busybox 镜像层 4.45MB。
  3. 总镜像大小:4.45 + 1.58 = 6.03MB

6.2.2 Dockerfile

单独建一个目录

bash 复制代码
[root@docker1 ~]# mkdir docker

作用

  1. 控制构建上下文,避免上传无关文件

    执行docker build -t xxx ..代表把当前目录全部文件打包传给 Docker 引擎。

    如果在/root家目录直接 build,root 下所有日志、脚本、缓存全部打包上传,速度慢、体积巨大,还会泄露文件。

    新建空目录,里面只放 Dockerfile、nginx.conf、tar 源码、repo 文件,上下文就只有需要的文件。

  2. 文件管理干净,不污染 root 家目录

    所有实验文件(Dockerfile、配置、源码)统一放在~/docker,找文件、删除实验内容很方便,不和系统文件混在一起。

  3. COPY 指令找文件不会乱

    COPY只能拿上下文目录里面的文件,不能拿外面上级目录的文件。把所有素材全部放进这个文件夹,COPY 直接写文件名即可。

  4. 方便区分多个项目

    还可以继续建子目录:mkdir nginx_buildmkdir python_build,每个镜像构建单独一套目录。

构建上下文目录:把宿主机CentOS‑Base.repo源文件复制到 ~/docker 目录

bash 复制代码
[root@docker1 ~]# cd /etc/yum.repos.d/
[root@docker1 yum.repos.d]# cp CentOS-Base.repo ~/docker/

确保资源文件都在当前目录

bash 复制代码
[root@docker1 yum.repos.d]# cd
[root@docker1 ~]# cd docker/
[root@docker1 docker]# ls
centos7.tar  CentOS-Base.repo  nginx-1.30.3.tar.gz

导入本地centos7镜像包

bash 复制代码
[root@docker1 docker]# docker load -i centos7.tar
[root@docker1 docker]# rm -fr centos7.tar
# 删除本地tar包,释放磁盘

编写 Dockerfile

bash 复制代码
[root@docker1 docker]# vim Dockerfile
复制代码
FROM centos:7
RUN rm -f /etc/yum.repos.d/*.repo
COPY CentOS‑Base.repo /etc/yum.repos.d/
RUN yum install -y gcc make pcre‑devel openssl‑devel
ADD nginx‑1.30.3.tar.gz /mnt/
WORKDIR /mnt/nginx‑1.30.3
RUN sed -i 's/CFLAGS="$CFLAGS -g"/#CFLAGS="$CFLAGS -g"/g' auto/cc/gcc
RUN ./configure --with‑http_ssl_module --with‑http_stub_status_module
RUN make
RUN make install
EXPOSE 80
CMD ["/usr/local/nginx/sbin/nginx","‑g","daemon off;"]
`daemon off;` 让 Nginx以前台方式运行,不脱离终端。
Nginx 就成为容器的 PID 1 主进程,进程在,容器就存活。

执行镜像构建,读取 Dockerfile 逐层生成镜像

-t webserver:v1‑t 打标签(tag),镜像名 webserver,版本标签 v1

bash 复制代码
[root@docker1 docker]# docker build -t webserver:v1 .

过滤显示仓库名为webserver的所有镜像

bash 复制代码
[root@docker1 docker]# docker images webserver

基于镜像webserver:v1创建一个名叫web1的容器,后台启动

bash 复制代码
[root@docker1 docker]# docker run -d --name web1 webserver:v1
[root@docker1 docker]# docker ps

查看容器web1的完整底层 JSON 格式元数据。

包含:容器 ID、状态、网络、端口映射、挂载、环境变量、镜像 ID、进程、文件路径等全部底层信息

bash 复制代码
[root@docker1 docker]# docker inspect web1

172.17.0.2:容器 web1 在 docker 默认 bridge 网桥里的容器内网 IP

测试

bash 复制代码
[root@docker1 docker]# curl 172.17.0.2

查看日志

bash 复制代码
[root@docker1 docker]# docker logs web1
# docker logs 读取的是容器进程的 stdout、stderr(标准输出、标准错误);编译安装的 Nginx 默认把日志写入磁盘文件,不打印到标准输出
[root@docker1 docker]# docker exec -it web1 bash
# 交互式进入容器内部
[root@c3540f688ac3 nginx-1.30.3]# cd /usr/local/nginx/logs
# 在此目录下可看到日志

7 镜像优化

7.1 缩减镜像层

在 v1 版本中,每一个RUN生成一个独立镜像层,这里 yum、sed、configure、make、make install 都是单独 RUN ,镜像层数非常多;yum 安装完没有清理 yum 缓存,缓存文件留在镜像层,镜像体积大;nginx 源码解压包/mnt/nginx‑1.30.3编译完成后还留在镜像里,占磁盘空间

bash 复制代码
[root@docker1 docker]# docker rm -f web1
[root@docker1 docker]# vim Dockerfile

在 v2 版本中,可以做以下优化

bash 复制代码
FROM centos:7
RUN rm -f /etc/yum.repos.d/*.repo
COPY CentOS‑Base.repo /etc/yum.repos.d/
ADD nginx‑1.30.3.tar.gz /mnt/

# 全部编译流程合并为 1 条RUN
RUN yum install -y gcc make pcre‑devel openssl‑devel \
&& cd /mnt/nginx‑1.30.3 \
&& sed -i 's/CFLAGS="$CFLAGS -g"/#CFLAGS="$CFLAGS -g"/g' auto/cc/gcc \
&& ./configure --with‑http_ssl_module --with‑http_stub_status_module \
&& make \
&& make install \
&& cd .. \
&& rm -fr nginx‑1.30.3 \       # 删除nginx源码包,删掉编译残留文件
&& yum clean all                # 清理yum缓存,减小镜像大小

EXPOSE 80
CMD ["/usr/local/nginx/sbin/nginx","‑g","daemon off;"]

构建 v2 版本镜像

bash 复制代码
[root@docker1 docker]# docker build -t webserver:v2 .

镜像体积明显变小

bash 复制代码
[root@docker1 docker]# docker images webserver

运行容器,没问题

bash 复制代码
[root@docker1 docker]# docker run -d --name web1 webserver:v2
[root@docker1 docker]# docker ps

测试

7.2 多阶段构建

多阶段构建原理

一份 Dockerfile 可以写多个FROM,每一个FROM代表一个独立阶段

  1. 构建阶段(builder):用完整基础镜像,安装编译工具,下载源码,编译出可执行程序。这个阶段只负责 "生产成品"。
  2. 运行阶段(最终镜像) :重新开启一个全新干净的基础镜像,只把编译好的成品文件从 builder 复制过来。

builder 阶段的所有编译器、源码、临时文件全部直接丢弃,不会进入最终镜像,最终镜像只保留运行业务程序必须的文件

重新进入容器,将nginx.conf文件拷贝到容器

bash 复制代码
[root@docker1 docker]# docker rm -f web1
web1
[root@docker1 docker]# docker run -it --name web1 webserver:v2 bash

若 web1 容器还在运行中,可执行docker exec -it web1 bash直接进入

bash 复制代码
[root@a98b205e6240 /]# cd /usr/local/nginx/conf/
ctrl+pq 退出容器,但不停止容器,回到宿主机 shell,容器继续后台运行
[root@a98b205e6240 conf]# [root@docker1 docker]# docker cp web1:/usr/local/nginx/conf/nginx.conf ./nginx.conf
bash 复制代码
[root@docker1 docker]# docker rm -f web1
[root@docker1 docker]# vim nginx.conf
复制代码
error_log  /dev/stderr notice;
# nginx 错误日志输出到**标准错误**,日志级别`notice`及以上输出

log_format main ...; # 定义main格式日志模板
access_log /dev/stdout main; # 访问日志输出到标准输出,使用main格式

在 Docker 容器中,写入这两个文件的内容,就会被 Docker 引擎捕获,通过 `docker logs 容器名` 查看日志,**不用写磁盘文件**
bash 复制代码
[root@docker1 docker]# vim Dockerfile
复制代码
#第一阶段build编译阶段:编译nginx
FROM centos:7 as build
RUN rm -f /etc/yum.repos.d/*.repo
COPY CentOS-Base.repo /etc/yum.repos.d/
ADD nginx-1.30.3.tar.gz /mnt/
RUN yum install -y gcc make pcre-devel openssl-devel && cd /mnt/nginx-1.30.3 && sed -i 's/CFLAGS="$CFLAGS -g"/#CFLAGS="$CFLAGS -g"/g' auto/cc/gcc && ./configure --with-http_ssl_module --with-http_stub_status_module && make && make install && cd .. && rm -fr nginx-1.30.3 && yum clean all
COPY nginx.conf /usr/local/nginx/conf/

#第二阶段最终镜像,重新拉取一个干净纯净的 centos:7 基础镜像,复制编译产物,舍弃编译工具
FROM centos:7
COPY --from=build /usr/local/nginx /usr/local/nginx
# 引用上面叫 build 的那个阶段,把编译好的文件拷贝过来
EXPOSE 80
CMD ["/usr/local/nginx/sbin/nginx","-g","daemon off;"]

根据当前目录的 Dockerfile 编译生成名为 webserver:v3 的Nginx镜像

bash 复制代码
[root@docker1 docker]# docker build -t webserver:v3 .

查看各个版本的 webserver 镜像,v3 体积又被压缩

bash 复制代码
[root@docker1 docker]# docker images webserver

运行容器

bash 复制代码
[root@docker1 docker]# docker run -d --name web1 webserver:v3
[root@docker1 docker]# docker ps
[root@docker1 docker]# docker logs web1
# 日志可直接查看

7.3 使用最精简的基础镜像

精简镜像也常叫 Distroless(无发行版)镜像,只保留业务程序运行必需的二进制文件、依赖库,剔除操作系统 shell、包管理器、调试工具、文档等无关组件

优点

  1. 体积小:去掉大量系统工具,镜像大小大幅下降,传输、部署速度更快。
  2. 安全性高:减少系统组件,攻击面变小;即使攻击者入侵容器,没有 shell、curl 等工具,很难执行恶意命令。
  3. 环境干净:只保留业务运行最低限度依赖,避免系统自带工具带来版本冲突。

缺点

  1. 无法使用 docker exec 调试 :镜像内部没有sh/bash,也没有curlss、netstat 等排错工具,docker exec执行命令直接报executable file not found
  2. 排错困难:不能进入容器内部修改配置、查看文件;配置错误只能在宿主机修改源码,重新 build 镜像。
  3. 故障排查手段有限 :只能依靠容器日志、nsenter切入命名空间、宿主机抓包等外部方式排错。

导入基础镜像

bash 复制代码
[root@docker1 ~]# docker load -i base-debian12.tar
[root@docker1 ~]# mkdir new
[root@docker1 ~]# cd new/
[root@docker1 new]# docker tag docker.1ms.run/nginx nginx:latest
[root@docker1 new]# docker rmi docker.1ms.run/nginx:latest
[root@docker1 new]# vim Dockerfile
bash 复制代码
[root@docker1 new]# docker build -t webserver:v4 .
bash 复制代码
[root@docker1 new]# docker run -d --name web1  webserver:v4

日志

相关推荐
大模型丫丫1 小时前
Hermes Agent:轻量级智能体框架实战指南
大数据·运维·服务器
考虑考虑1 小时前
kubectl命令
运维·后端·自动化运维
NJCloud1 小时前
Docker 容器技术入门:部署、核心概念与基础命令
运维·docker·容器
2601_962072332 小时前
docker自建rustdesk-server远程桌面
运维·docker·容器
Blockchina2 小时前
Codex 实战:从一句需求到可验收的 Linux 主机巡检脚本
运维·服务器·网络
2601_962218472 小时前
万象生鲜系统冷链物联网接入技术实现生鲜企业温控管理数字化
大数据·运维·微服务·云原生·架构
Best-Wishes3 小时前
BurpSuite Pro教育版在linux系统中配置
linux·运维·服务器·网络安全·burpsuite
pnoker3 小时前
从零部署 IoT DC3:四步快速启动实录
物联网·docker·部署
wuminyu3 小时前
深入剖析 Panama Off-heap 的性能损耗与开销
java·linux·c语言·jvm·c++