Dockerfile 深入浅出:从基础到进阶全解析

Dockerfile 深入浅出:从基础到进阶全解析

各位同学,大家好!欢迎来到今天的 Dockerfile 课程。Docker 技术在当今的软件开发和部署领域可以说是非常热门,而 Dockerfile 作为构建 Docker 镜像的关键文件,掌握它对于我们进行容器化开发和部署至关重要。今天,我将用最通俗易懂的语言,从基础到进阶,结合常见例子,带大家全面深入地学习 Dockerfile 的编写。这份教程非常实用,建议大家收藏,跟着我一起实操,会更容易理解。

一、Dockerfile基础入门

1. 什么是 Dockerfile?

Dockerfile 是一个文本文件,它包含了构建 Docker 镜像的所有指令。怎么理解呢?我们可以把它类比成菜谱。想象一下,厨师(Docker 引擎)就像是按照菜谱上的步骤来制作菜品(镜像)。Dockerfile 中的每一条指令就像是菜谱中的一个步骤,告诉 Docker 引擎该怎么做。

2. 第一个 Dockerfile 示例:静态网站(Nginx)
需求理解

我们的目标是使用 Docker 和 Nginx 来部署一个静态网站。静态网站通常由 HTML、CSS、JavaScript 文件以及一些图片等资源组成。我们要通过 Dockerfile 构建一个包含 Nginx 服务器和静态网站文件的镜像,然后运行容器来对外提供服务。

所需文件及目录结构

首先,我们需要创建一个项目目录,例如 nginx-static,并在该目录下创建必要的文件和文件夹。来看一下详细的目录结构:

nginx-static/
├── dist
│   ├── index.html
│   ├── script.js
│   └── style.css
└── Dockerfile1 directory, 4 files
具体文件内容
  • dist/index.html:这是静态网站的主页文件,使用简单的 HTML 代码展示一个基本的页面。其中包含了对 CSS 和 JavaScript 文件的引用。
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><link rel="stylesheet" href="style.css"><title>My Static Website</title>
</head><body><h1>Welcome to My Static Website</h1><p>This is a simple static website deployed with Docker and Nginx.</p><script src="script.js"></script>
</body></html>
  • dist/style.css:这是一个简单的 CSS 文件,用于为页面添加一些基本的样式,比如设置字体、背景颜色、文本对齐方式等。
body {font-family: Arial, sans-serif;background-color: #f4f4f4;text-align: center;padding-top: 50px;
}h1 {color: #333;
}p {color: #666;
}
  • dist/script.js:这是一个简单的 JavaScript 文件,在页面加载完成后会弹出一个提示框,让用户知道页面已经加载成功。
window.onload = function () {alert('Welcome to my static website!');
};
  • Dockerfile:这个 Dockerfile 用于构建包含 Nginx 服务器和静态网站文件的镜像。让我们来逐行分析一下:
# 使用官方的 Nginx 基础镜像,基于 Alpine 版本,体积较小
FROM nginx:alpine# 将本地的 dist 目录下的所有文件复制到 Nginx 容器内的 HTML 目录中
COPY dist/ /usr/share/nginx/html# 暴露容器的 80 端口,这是 Nginx 默认的 HTTP 服务端口
EXPOSE 80

FROM 指令指定了基础镜像,这里我们使用的是官方的 Nginx 基础镜像,基于 Alpine 版本,它的体积比较小,这样构建出来的镜像也会比较小。COPY 指令将本地的 dist 目录下的所有文件复制到 Nginx 容器内的 HTML 目录中,这样 Nginx 就可以找到我们的静态网站文件了。EXPOSE 指令声明了容器使用的端口,这里是 80 端口,这是 Nginx 默认的 HTTP 服务端口。

构建镜像

在项目根目录(nginx-static)下,打开终端并执行以下命令来构建 Docker 镜像:

docker build -t nginx-static-image .
  • -t 选项用于给镜像指定一个标签,这里我们将镜像命名为 nginx-static-image
  • . 表示使用当前目录作为构建上下文。
运行容器

构建完成后,我们可以使用以下命令来运行容器:

docker run -d -p 8080:80 nginx-static-image
  • -d 选项表示在后台运行容器。
  • -p 选项用于将宿主机的端口(这里是 8080)映射到容器的端口(这里是 80)。
  • nginx-static-image 是我们之前构建的镜像名称。
验证网站

打开浏览器,访问 http://localhost:8080,如果一切正常,你应该能够看到静态网站的页面,并且在页面加载完成后会弹出一个提示框。我们也可以使用 curl 命令来验证

[root@C9 Docker]# curl http://localhost:8080
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><link rel="stylesheet" href="style.css"><title>My Static Website</title>
</head><body><h1>Welcome to My Static Website</h1><p>This is a simple static website deployed with Docker and Nginx.</p><script src="script.js"></script>
</body></html>

在这里插入图片描述

二、核心指令详解(打好基础)

1. 镜像构建指令
指令用途示例
FROM指定基础镜像(必须是第一条指令)FROM ubuntu:22.04
COPY复制文件到容器(推荐使用)COPY src/ /app/src
ADD比COPY多支持URL和自动解压tar包(不推荐)ADD https://example.com/file
RUN执行命令(会生成新镜像层)RUN apt-get update && …

FROM 指令用于指定基础镜像,它是 Dockerfile 中必须的第一条指令,因为所有的镜像构建都是基于一个已有的基础镜像。COPY 指令用于将本地文件或目录复制到容器中,它的语法比较简单,只需要指定源路径和目标路径就可以了。ADD 指令虽然比 COPY 多了一些功能,比如支持 URL 和自动解压 tar 包,但是由于它的功能比较复杂,容易引入一些安全问题,所以一般不推荐使用。RUN 指令用于在容器中执行命令,它会生成一个新的镜像层,所以在使用 RUN 指令时要注意尽量合并多个命令,减少镜像层的数量。

2. 容器运行指令
指令用途示例
CMD容器启动时执行的默认命令(可被docker run覆盖)CMD [“python”, “app.py”]
ENTRYPOINT容器启动时执行的固定命令(参数可追加)ENTRYPOINT [“/app/start.sh”]
EXPOSE声明容器使用的端口(需配合docker run -p映射)EXPOSE 80 443
VOLUME创建数据卷(容器外存储数据)VOLUME [“/var/lib/mysql”]

CMD 指令用于指定容器启动时执行的默认命令,它可以被 docker run 命令中的参数覆盖。ENTRYPOINT 指令用于指定容器启动时执行的固定命令,它的参数可以追加。EXPOSE 指令用于声明容器使用的端口,但是它只是一个声明,并不会实际进行端口映射,需要配合 docker run -p 选项来进行端口映射。VOLUME 指令用于创建数据卷,数据卷可以将容器内的数据存储到容器外,这样即使容器被删除,数据也不会丢失。

3. 环境配置指令
指令用途示例
WORKDIR设置当前工作目录(相当于连续执行cd命令)WORKDIR /app && WORKDIR src
ENV设置环境变量ENV FLASK_ENV=production
USER指定运行命令的用户(提高安全性)USER appuser

WORKDIR 指令用于设置当前工作目录,它相当于在容器中连续执行 cd 命令。ENV 指令用于设置环境变量,环境变量可以在容器中被应用程序使用。USER 指令用于指定运行命令的用户,这样可以提高容器的安全性。

三、实战进阶技巧(大厂常用)

1. 构建缓存优化
# 先复制依赖文件,利用Docker缓存
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt# 再复制代码(代码修改时不会触发依赖重新安装)
COPY . .

在构建镜像时,Docker 会使用缓存来加速构建过程。如果我们把依赖文件和代码一起复制到容器中,那么只要代码有任何修改,就会导致依赖文件也被重新复制,从而触发依赖重新安装,这样会浪费很多时间。所以我们可以先复制依赖文件,安装依赖,然后再复制代码,这样当代码修改时,依赖安装的步骤就可以利用缓存,不会被重新执行。

2. 多阶段构建(减小镜像体积)
# 第一阶段:编译应用
FROM python:3.10-slim AS builder
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
RUN python setup.py build# 第二阶段:最终镜像(仅包含运行时文件)
FROM python:3.10-slim
WORKDIR /app
COPY --from=builder /app/dist /app/dist
CMD ["python", "/app/dist/main.py"]

在构建镜像时,Docker 会使用缓存来加速构建过程。如果我们把依赖文件和代码一起复制到容器中,那么只要代码有任何修改,就会导致依赖文件也被重新复制,从而触发依赖重新安装,这样会浪费很多时间。所以我们可以先复制依赖文件,安装依赖,然后再复制代码,这样当代码修改时,依赖安装的步骤就可以利用缓存,不会被重新执行。

3. 健康检查
HEALTHCHECK --interval=5s --timeout=3s \CMD curl -f http://localhost:8000/health || exit 1

健康检查可以帮助我们监控容器的运行状态。HEALTHCHECK 指令用于定义一个健康检查命令,--interval 选项指定检查的间隔时间,--timeout 选项指定检查的超时时间。如果健康检查命令返回非零退出码,Docker 会认为容器不健康。

4. 动态参数(ARG)
ARG APP_VERSION=1.0.0
ENV APP_VERSION=$APP_VERSION# 构建时指定参数
docker build --build-arg APP_VERSION=2.0.0 -t myapp .

ARG 指令用于定义一个构建时参数,这个参数可以在构建镜像时通过 --build-arg 选项来指定。我们可以使用 ENV 指令将 ARG 定义的参数设置为环境变量,这样应用程序就可以使用这个环境变量了。

四、进阶案例:Python Flask 应用详细部署

1. 需求理解

我们要使用 Docker 来部署一个基于 Python Flask 框架开发的 Web 应用。Flask 是一个轻量级的 Web 框架,非常适合快速开发小型 Web 应用。通过 Dockerfile 构建一个包含 Python 环境和 Flask 应用的镜像,然后运行容器来对外提供服务。

2. 所需文件及目录结构

首先,创建一个项目目录,例如 flask-app,并在该目录下创建必要的文件和文件夹。以下是详细的目录结构:

flask-app/
├── app.py
├── Dockerfile
└── requirements.txt0 directories, 3 files
4. 具体文件内容
  • app.py:这是 Flask 应用的主文件,定义了一个简单的路由,当访问根路径时返回 “Hello, World!”。
from flask import Flaskapp = Flask(__name__)@app.route('/')
def hello_world():return 'Hello, World!'if __name__ == '__main__':app.run(host='0.0.0.0', port=5000)
  • requirements.txt:这个文件记录了项目所需的 Python 依赖包,这里只需要 Flask。
flask
  • Dockerfile:这个 Dockerfile 用于构建包含 Python 环境和 Flask 应用的镜像。
# 使用官方的 Python 3.10 轻量级基础镜像
FROM python:3.10-slim# 设置工作目录
WORKDIR /app# 复制依赖文件到工作目录
COPY requirements.txt .# 安装依赖包,使用 --no-cache-dir 选项避免缓存占用过多空间
RUN pip install --no-cache-dir -r requirements.txt# 复制项目代码到工作目录
COPY . .# 暴露容器的 5000 端口,这是 Flask 应用默认的服务端口
EXPOSE 5000# 定义容器启动时执行的命令
CMD ["python", "app.py"]
5. 构建镜像

在项目根目录(flask-app)下,打开终端并执行以下命令来构建 Docker 镜像:

docker build -t flask-app-image .
  • -t 选项用于给镜像指定一个标签,这里我们将镜像命名为 flask-app-image
  • . 表示使用当前目录作为构建上下文。
6. 运行容器

构建完成后,我们就可以运行容器了。使用以下命令:

docker run -d -p 8081:5000 flask-app-image
  • -d 选项表示在后台运行容器。
  • -p 选项用于将宿主机的端口(这里是 8081)映射到容器的端口(这里是 5000)。
  • flask-app-image 是我们之前构建的镜像名称。
7. 验证应用

打开浏览器,访问 http://localhost:8081,如果一切正常,你应该能够看到页面显示 “Hello, World!”。

进阶优化

多阶段构建

为了减小镜像体积,我们可以使用多阶段构建。来看一下优化后的 Dockerfile:

# 第一阶段:构建环境,安装依赖
FROM python:3.10-slim AS builder
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt# 第二阶段:最终镜像,只包含运行所需的文件
FROM python:3.10-slim
WORKDIR /app
COPY --from=builder /usr/local/lib/python3.10/site-packages /usr/local/lib/python3.10/site-packages
COPY . .
EXPOSE 5000
CMD ["python", "app.py"]

这里我们分为两个阶段。第一阶段使用 AS builder 命名为构建环境,安装所需的依赖。第二阶段是最终镜像,只复制第一阶段安装好的依赖和项目代码,这样可以大大减小镜像体积。

健康检查

我们还可以在 Dockerfile 中添加健康检查,确保应用正常运行。

# 第一阶段:构建环境,安装依赖
FROM python:3.10-slim AS builder
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt# 第二阶段:最终镜像,只包含运行所需的文件
FROM python:3.10-slim
WORKDIR /app
COPY --from=builder /usr/local/lib/python3.10/site-packages /usr/local/lib/python3.10/site-packages
COPY . .
EXPOSE 5000# 添加健康检查,每 10 秒检查一次,超时时间为 3 秒,最多重试 3 次
HEALTHCHECK --interval=10s --timeout=3s --retries=3 \CMD curl -f http://localhost:5000/ || exit 1CMD ["python", "app.py"]

通过 HEALTHCHECK 指令,我们可以设置每 10 秒检查一次应用的健康状态,超时时间为 3 秒,最多重试 3 次。如果检查失败,容器会被标记为不健康。

五、避坑指南

在使用 Docker 构建镜像和运行容器的过程中,有一些常见的坑需要我们注意。

  1. 避免安装不必要的包:尽量使用 slimalpine 基础镜像,这样可以减少镜像体积。

  2. 不要使用 root 用户:为了安全起见,我们可以添加普通用户来运行容器。

    RUN useradd -m appuser && chown -R appuser /app
    USER appuser
    
  3. 清理缓存:安装完成后,记得删除包管理器的缓存。

    RUN apt-get update && apt-get install -y wget && rm -rf /var/lib/apt/lists/*
    
  4. 区分 CMD 和 ENTRYPOINT:

    • CMD:容器启动时执行的默认命令,这个命令是可以被覆盖的。
    • ENTRYPOINT:是固定执行的命令,参数可以追加。

总结

最后,我们来总结一下。Dockerfile 的核心原则是分层构建缓存利用。通过合理的指令顺序和镜像优化,我们能显著提升构建效率和镜像安全性。建议大家在实际项目中多尝试不同的配置,观察构建日志中的缓存命中情况,逐步积累经验。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/29428.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

视频录像机视频通道是指什么

视频录像机的视频通道是指摄像机在监控矩阵或硬盘录像机设备上的视频输入的物理位置。 与摄像头数量关系&#xff1a;在视频监控系统中&#xff0c;有多少个摄像头就需要多少路视频通道&#xff0c;通道数量决定了视频录像机可接入摄像头的数量&#xff0c;一般硬盘录像机有4路…

2025-03-06 学习记录--C/C++-PTA 习题6-6 使用函数输出一个整数的逆序数

合抱之木&#xff0c;生于毫末&#xff1b;九层之台&#xff0c;起于累土&#xff1b;千里之行&#xff0c;始于足下。&#x1f4aa;&#x1f3fb; 一、题目描述 ⭐️ 二、代码&#xff08;C语言&#xff09;⭐️ #include <stdio.h>int reverse( int number );int main…

游戏引擎学习第138天

仓库:https://gitee.com/mrxiao_com/2d_game_3 资产&#xff1a;game_hero_test_assets_003.zip 发布 我们的目标是展示游戏运行时的完整过程&#xff0c;从像素渲染到不使用GPU的方式&#xff0c;我们自己编写了渲染器并完成了所有的工作。今天我们开始了一些新的内容&#…

LeetCode hot 100—二叉树的最大深度

题目 给定一个二叉树 root &#xff0c;返回其最大深度。 二叉树的 最大深度 是指从根节点到最远叶子节点的最长路径上的节点数。 示例 示例 1&#xff1a; 输入&#xff1a;root [3,9,20,null,null,15,7] 输出&#xff1a;3示例 2&#xff1a; 输入&#xff1a;root [1,n…

力扣刷题DAY6(滑动窗口/中等+栈/简单、中等)

一、滑动窗口 找到字符串中所有字母异位词 方法一&#xff1a;哈希表 class Solution { public:vector<int> findAnagrams(string s, string p) {vector<int> ans;unordered_map<char, int> target;for (int i 0; i < p.size(); i) {target[p[i]];}in…

DeepSeek V3 源码:从入门到放弃!

从入门到放弃 花了几天时间&#xff0c;看懂了DeepSeek V3 源码的逻辑。源码的逻辑是不难的&#xff0c;但为什么模型结构需要这样设计&#xff0c;为什么参数需要这样设置呢&#xff1f;知其然&#xff0c;但不知其所以然。除了模型结构以外&#xff0c;模型的训练数据、训练…

thinkphp5.1 在fetch模版就超时

场景 当被渲染模版不存在&#xff0c;请求不响应任何内容&#xff0c;过一会就timeout 排查过程 使用xdebug,追踪代码&#xff0c;发现走到D:\temporary_files\m40285_mini\40285_mini\thinkphp\library\think\exception\Handle.php&#xff0c;进入死循环&#xff0c;一直…

【Vue CLI脚手架开发】——6.scoped样式

文章目录 一、scoped是什么二、应用案例1.使用代码2.原理3父组件App未添加scoped影响 一、scoped是什么 我们知道vue为了防止css样式污染&#xff0c;在每个组件中提供了 scoped属性进行限定css作用域&#xff1b;当<style>标签有 scoped 属性时&#xff0c;它的 CSS 只…

微服务,服务治理nacos,负载均衡LOadBalancer,OpenFeign

1.微服务 简单来说&#xff0c;微服务架构风格[1]是一种将一个单一应用程序开发为一组小型服务的方法&#xff0c;每个服务运行在 自己的进程中&#xff0c;服务间通信采用轻量级通信机制(通常用HTTP资源API)。这些服务围绕业务能力构建并 且可通过全自动部署机制独立部署。这…

STM32-USART串口数据包

一&#xff1a;HEX数据包发送 1.为了收发数据包&#xff0c;先定义两个缓存区的数组 &#xff0c;这4个数据只存储发送或者接收的载荷数据&#xff0c;包头和包尾不存 uint8_t Serial_TxPacket[4]; uint8_t Serial_RxPacket[4]; uint8_t Serial_RxFlag;//接收一个数据包就置F…

[项目]基于FreeRTOS的STM32四轴飞行器: 四.LED控制

基于FreeRTOS的STM32四轴飞行器: 四.LED控制 一.配置Com层二.编写驱动 一.配置Com层 先在Com_Config.h中定义灯位置的枚举类型&#xff1a; 之后定义Led的结构体&#xff1a; 定义飞行器状态&#xff1a; 在Com_Config.c中初始化四个灯&#xff1a; 在Com_Config.h外部声明…

RT-DETR融合YOLOv12中的R-ELAN结构

RT-DETR使用教程&#xff1a; RT-DETR使用教程 RT-DETR改进汇总贴&#xff1a;RT-DETR更新汇总贴 《YOLOv12: Attention-Centric Real-Time Object Detectors》 一、 模块介绍 论文链接&#xff1a;https://arxiv.org/abs/2502.12524 代码链接&#xff1a;https://gitcode.com…

“深入浅出”系列之Linux篇:(13)socket编程实战+TCP粘包解决方案

从日常使用的APP&#xff0c;到背后支撑的各类服务器&#xff0c;网络通信无处不在&#xff0c;而socket作为实现网络通信的关键技术&#xff0c;更是开发者们必须掌握的核心知识。但在socket编程的道路上&#xff0c;TCP粘包问题宛如一只拦路虎&#xff0c;让无数开发者头疼不…

【计算机操作系统】操作系统的功能和目标

1、操作系统的功能和目标---作为系统资源的管理者 作为系统资源的管理者提供的功能&#xff1a; &#xff08;1&#xff09;处理机管理 &#xff08;2&#xff09;存储器管理 &#xff08;3&#xff09;文件管理 &#xff08;4&#xff09;设备管理 作为系统资源的管理者…

“深入浅出”系列之Linux篇:(10)基于C++实现分布式网络通信RPC框架

分布式网络通信rpc框架 项目是分布式网络通信rpc框架&#xff0c; 文中提到单机服务器的缺点&#xff1a; 硬件资源的限制影响并发&#xff1a;受限于硬件资源&#xff0c;聊天服务器承受的用户的并发有限 模块的编译部署难&#xff1a;任何模块小的修改&#xff0c;都导致整…

Aws batch task 无法拉取ECR 镜像unable to pull secrets or registry auth 问题排查

AWS batch task使用了自定义镜像&#xff0c;在提作业后出现错误 具体错误是ResourceInitializationError: unable to pull secrets or registry auth: The task cannot pull registry auth from Amazon ECR: There is a connection issue between the task and Amazon ECR. C…

机器学习之无监督学习

无监督学习&#xff08;Unsupervised Learning&#xff09;是机器学习的一个重要分支&#xff0c;其特点是在训练过程中不使用标签数据。与有监督学习不同&#xff0c;无监督学习的目标是从未标记的数据中发现隐藏的结构、模式或关系。无监督学习广泛应用于聚类、降维、异常检测…

自然语言处理:朴素贝叶斯

介绍 大家好&#xff0c;博主又来和大家分享自然语言处理领域的知识了。按照博主的分享规划&#xff0c;本次分享的核心主题本应是自然语言处理中的文本分类。然而&#xff0c;在对分享内容进行细致梳理时&#xff0c;我察觉到其中包含几个至关重要的知识点&#xff0c;即朴素…

HTML label 标签使用

点击 <label> 标签通常会使与之关联的表单控件获得焦点或被激活。 通过正确使用 <label> 标签&#xff0c;可以使表单更加友好和易于使用&#xff0c;同时提高整体的可访问性。 基本用法 <label> 标签通过 for 属性与 id 为 username 的 <input> 元素…

Ubuntu20.04双系统安装及软件安装(五):VSCode

Ubuntu20.04双系统安装及软件安装&#xff08;五&#xff09;&#xff1a;VSCode 打开VScode官网&#xff0c;点击中间左侧的deb文件下载&#xff1a; 系统会弹出下载框&#xff0c;确定即可。 在文件夹的**“下载”目录**&#xff0c;可看到下载的安装包&#xff0c;在该目录下…