示例1:Python Flask Web应用

# 1. 基础镜像
FROM python:3.9-slim

# 2. 设置环境变量
ENV PYTHONUNBUFFERED=1 \
    FLASK_APP=app.py \
    FLASK_ENV=production \
    PORT=5000

# 3. 设置工作目录
WORKDIR /app

# 4. 安装系统依赖(需要root权限)
RUN apt-get update && \
    apt-get install -y --no-insa=tall-recommends \
    gcc \
    python3-dev && \
    apt-get clean && \
    rm -rf /var/lib/apt/lists/*

# 5. 复制依赖文件
COPY requirements.txt .

# 6. 安装Python依赖
RUN pip install --no-cache-dir -r requirements.txt

UN useradd -m -u 1000 -s /bin/bash appuser

# 8. 复制应用代码
COPY --chown=appuser:appuser . .

# 9. 创建数据卷
VOLUME ["/app/logs", "/app/uploads"]

# 10. 切换到非root用户
USER appuser

# 11. 声明暴露端口
EXPOSE 5000

# 12. 健康检查
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
    CMD curl -f http://localhost:5000/health || exit 1

# 13. 启动命令
CMD ["gunicorn", "--bind", "0.0.0.0:5000", "app:app"]
  • 1. FLASK 是一个轻量级的python web框架(只能用作python),提供了构建网站和API所需的基本工具,可以不用从零开始写所有代码
  • 2. 环境变量

        1)PYTHONUNBUFFERED=1 禁用python输出缓冲,设置日志实时输出,无延时

        2)FLASK_APP=该应用的启动文件,从这个文件开始启动

  • 4. 安装系统依赖

        1)操作符:

                cmd1 && cmd2:        前一个成功才执行后一个,依赖顺序的命令

                `cmd1 [换行] cmd2`: 前一个失败才执行后一个,备用方案

                cmd1;cmd2:           无论成败都执行后一个,独立命令

                cmd1 & cmd2:          在后台执行,并行任务

        2)install -y --no-install-recommends:提示默认选择yes;

        3)大部分python包都需要C扩展,所以要下载gcc

        4)python3-dev:用来提供python C API头文件

        5)/var/lib/apt/lists/*:镜像包含软件包列表缓存的地方,rm可以节省空间

  • 6. --no-cache-dir -r requirements.txt:下载安装后立即删除缓存;从requirement.txt安装依赖
  • 7. -m -u 1000 -s /bin/bash appuser:创建用户的家目录;规定UID为1000;设置登录shell为bash(而不是默认的sh),提供更丰富的命令行功能;appuser为用户名
  • 8. --chown=appuser:appuser:将复制过来的文件都设置为该用户/用户组
  • 12. 容器启动---等待5s(start-period)---健康检查:curl http://localhost:5000/health

        1)timeout:若是3s没有相应,就失败一次

        2)interval:失败后,先等待30s,再去尝试

        3)retries:最多只能失败3次,就代表不健康

        4)curl -f  || exit 1:失败时返回非零状态码;当返回非零状态码就exit 1

        执行 curl -f http://localhost:5000/health
        ↓
        如果成功(返回 0)→ 健康检查通过 ✅
        ↓  
        如果失败(返回非 0)→ 执行 exit 1 → 健康检查失败 ❌

示例2:Node.js React 前端应用

docker build -t my-app

# 1. 多阶段构建:构建阶段
FROM node:16-alpine AS builder

# 2. 设置环境变量
ENV NODE_ENV=production

# 3. 设置工作目录
WORKDIR /app

# 4. 复制依赖文件
COPY package*.json ./

# 5. 安装依赖
RUN npm ci --only=production

# 6. 复制源代码
COPY . .

# 7. 构建应用
RUN npm run build

# 8. 多阶段构建:运行阶段
FROM nginx:alpine

# 9. 复制构建产物
COPY --from=builder /app/build /usr/share/nginx/html

# 10. 复制自定义nginx配置
COPY nginx.conf /etc/nginx/conf.d/default.conf

# 11. 创建非root用户(nginx镜像已创建nginx用户)
USER nginx

# 12. 声明暴露端口
EXPOSE 80

# 13. 启动命令(使用nginx默认CMD)
  • 0. Node.js+React前端应用=用JavaScript同时搞定前端页面和后端服务;

        1)React 向 Node.js发送HTTP请求/响应;Node.js再去调用数据库信息,传递给React,React再返回到页面中

        2)而HTML和CSS穿插在React中,React作为逻辑语言,设计页面的动态变化(如果怎样怎样,就使用这段HTML/CSS语句)

  • 1. 多阶段构建:

        1)构建builder阶段:       

                -- Docker会基于FROM node:16-alpine AS builder创建一个完整的中间镜像

                -- 这个镜像包含所有构建工具和依赖,用于生成构建产物

                -- 它在构建缓存中存在,但没有用户友好的标签

        2)构建最终阶段:       

                -- 从FROM nginx:alpine开始一个全新的、独立的镜像构建

                -- 使用COPY --from=builder从builder阶段的中间镜像复制构建产物

                -- 这个阶段只包含运行环境(如Nginx)和构建产物,不包含构建工具

        3)构建完成后:

                -- 最终镜像被标记为my-app:latest并推送到镜像仓库(如需要)

                -- builder阶段的中间镜像变成"悬空镜像"(dangling image)【如果中间镜像没有被其他镜像引用,就会变成悬空镜像】

                -- 可以使用docker image prune清理这些悬空镜像来释放磁盘空间

                -- 最终结果是:一个小巧、安全、只包含运行产物的生产级镜像

#只构建builder阶段,不构建最终阶段
docker build -t my-app:builder --target builder .
# 1.用来调试 npm run build失败原因;
# 2. 验证依赖安装、代码编译是否正确,但不关心最终的部署;
# 3. 保留构建环境,避免builder镜像变成悬空镜像,方便后续使用

# 完整构建整个Dockerfile,生成最终的生产镜像,builder成为悬空镜像
docker build -t my-app:latest
  • 4. 依赖文件的安装

        1)npm install:需要package.json,该文件里面说明了需要安装的依赖,但没有说明具体版本,会根据文件 安装指定范围内的最新版本,并更新lock文件,速度较慢【日常开发,需要添加、更新或移除依赖】

        2)npm ci:需要package.json和package-lock.josn,lock文件指定了需要安装的依赖及其版本,使用npm ci会根据文件直接安装,不更新lock文件,速度较快【在持续集成流水线、部署生产环境或与团队成员确保完全一致的依赖树时使用】

  • 7. RUN npm run build:根据配置文件,从入口文件开始,把整个项目的代码文件收集打包,并构建好,最终生成优化后的成品文件到配置文件工作目录中,文件夹名称由配置文件中的参数决定【在react中,默认输出文件夹名称为build】
  • 8. 没有任何命名,所以这个是最终镜像
  • 9. --from=builder /app/build:从同dockerfile中的阶段命名为builder的镜像中复制 /app/build文件(这样就实现了镜像中只有需要的产物,而没有多余的依赖工具)

示例3:Java Spring Boot应用

# 1. 多阶段构建:构建阶段
FROM maven:3.8.4-openjdk-11 AS builder

# 2. 设置工作目录
WORKDIR /build

# 3. 复制POM文件(利用Docker缓存层)
COPY pom.xml .

# 4. 下载依赖(单独步骤利用缓存)
RUN mvn dependency:go-offline

# 5. 复制源代码
COPY src ./src

# 6. 构建应用
RUN mvn package -DskipTests

# 7. 多阶段构建:运行阶段
FROM openjdk:11-jre-slim

# 8. 设置环境变量
ENV JAVA_OPTS="-Xmx512m -Xms256m" \
    SPRING_PROFILES_ACTIVE=production

# 9. 创建应用用户
RUN groupadd -r appgroup && useradd -r -g appgroup appuser

# 10. 设置工作目录
WORKDIR /app

# 11. 从构建阶段复制JAR文件
COPY --from=builder /build/target/*.jar app.jar

# 12. 创建数据卷
VOLUME ["/app/logs", "/app/config"]

# 13. 修改文件权限
RUN chown -R appuser:appgroup /app

# 14. 切换到非root用户
USER appuser

# 15. 声明暴露端口
EXPOSE 8080

# 16. 健康检查
HEALTHCHECK --interval=30s --timeout=3s --start-period=60s --retries=3 \
    CMD curl -f http://localhost:8080/actuator/health || exit 1

# 17. 启动命令
ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -jar app.jar"]
  • 0. Spring Boot = Java应用的"一键启动"工具包,让复杂的企业开发变得简单高效。
  • 4. mvn

        1)mvn dependency:go-offline 根据pom.xml文件下载依赖

        2)mvn package -DskipTests   打包构建整个代码文件

方面mvn (Java/Maven)npm run build (JavaScript/Node.js)
技术栈Java项目JavaScript/Node.js项目
配置文件pom.xmlpackage.json
构建工具Apache MavenWebpack/Vite/Rollup等
输出结果JAR/WAR文件静态HTML/JS/CSS文件
  • 5. 如果源代码有修改,就会从这里开始重新运行,进行更新,所以34要先运行,这样就不用重新下载依赖了
  • 8. Xmx:初始分配的内存大小;Xms:可增长到最大的内存;Xss:每个线程栈的内存
  • 9. 创建用户

        1)groupadd -r appgroup:创建一个名叫appgroup的系统组

        2)useradd -r -g appgroup appuser:创建一个名叫appuser的系统用户 -g指定用户组为appgroup

        3)系统与登录 用户/组的区别

方面系统级用户登录账户
用途运行服务/应用真人交互操作
登录❌ 不能登录系统✅ 可以登录系统
家目录通常没有或为空✅ 有完整的家目录
Shell通常为 /bin/false/bin/bash 等完整shell
UID范围1-999 (系统范围)1000+ (用户范围)
  • ENTRYPOINT:
        容器启动时:
        1. sh -c 启动一个shell进程
        2. shell看到 $JAVA_OPTS → 查找环境变量
        3. 找到 JAVA_OPTS="..."参数
        4. 执行该命令:java [JAVA_OPTS参数] -jar app.jar
          【以JAVA_OPTS参数来运行名为app.jar的可执行JAR包】
  • docker build -t my-image:创建镜像,将[参数]记录到ENTRYPOINT中
  • docker run my-image:运行镜像(也就是创建容器),运行参数

        


示例4:PostgreSQL 数据库

# 1. 使用官方PostgreSQL镜像
FROM postgres:13

# 2. 设置环境变量
ENV POSTGRES_DB=myapp \
    POSTGRES_USER=appuser \
    POSTGRES_PASSWORD=changeme \
    PGDATA=/var/lib/postgresql/data/pgdata

# 3. 复制初始化脚本
COPY init-scripts/ /docker-entrypoint-initdb.d/

# 4. 复制自定义配置
COPY postgresql.conf $PGDATA/postgresql.conf

# 5. 修改配置文件的权限
RUN chown postgres:postgres /etc/postgresql/postgresql.conf

# 6. 数据卷(PostgreSQL镜像已声明,这里显式说明)
VOLUME ["/var/lib/postgresql/data"]

# 7. 声明暴露端口
EXPOSE 5432

# 8. 使用postgres用户(镜像已创建)
USER postgres

# 9. 健康检查
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
    CMD pg_isready -U $POSTGRES_USER -d $POSTGRES_DB || exit 1

# 10. 使用基础镜像的CMD
  • 0. PostgreSQL:PostgreSQL 是一个功能强大的开源关系型数据库管理系统,用于安全可靠地存储和管理结构化数据。PostgreSQL ≈ MySQL的"增强专业版"
  • 2. PGDATA:设置SQL所有存储的数据的地方,统一位置,方便管理
  • 3. 在官方PostgreSQL中

        1)init-scripts目录结构:           

        init-scripts/
        ├── 01-create-database.sql    # 创建数据库
        ├── 02-create-tables.sql      # 创建表结构
        ├── 03-insert-data.sql        # 插入初始数据
        └── 04-setup-users.sh         # 配置用户权限

        2)/docker-entrypoint-initdb.d/:在该容器首次加载或者数据为空(主要看$PGDATA中是否为空)时,就会自动执行/docker-entrypoint-initdb.d/中的4个代码文件

  • 4. $PGDATA/postgresql.conf:在加载的时候,默认加载这个文件中的配置
  • 6. VOLUME:这里也是备份$PGDATA这个重要数据目录
  • 10.运行命令:如果需要自定义启动命令/参数就需要用CMD(如何启动);覆盖环境变量就是用ENV(在什么环境下启动)

示例5:Redis 缓存服务

# 1. 使用官方Redis镜像
FROM redis:6.2-alpine

# 2. 复制自定义配置
COPY redis.conf /usr/local/etc/redis/redis.conf

# 3. 创建数据目录
RUN mkdir -p /data && chown redis:redis /data

# 4. 数据卷
VOLUME ["/data"]

# 5. 声明暴露端口
EXPOSE 6379

# 6. 使用redis用户(镜像已创建)
USER redis

# 7. 启动命令(使用自定义配置)
CMD ["redis-server", "/usr/local/etc/redis/redis.conf"]
  • 0. Redis缓存服务:Redis 是一个基于内存的键值数据库,通过将常用数据存储在内存中来大幅提升访问速度,用作应用程序的缓存层。
  • 2. Redis配置文件路径:/usr/local/etc/redis/redis.conf

        1)配置文件:应用的完整操作手册-定义应用如何运行的所有规则和行为

        2)环境变量:运行的上下文参数-提供运行时的配置参数和条件

        简单来说,配置文件是“操作规程”;环境变量是“工作条件”

  • 7. CMD:

        1)redis-server:启动Redis服务器程序

        2)"/usr/local/etc/redis/redis.conf":规定配置文件

        3)固定搭配:redis-server 指定配置文件 = 以指定配置文件启动Redis服务器程序


示例6:Go 微服务

# 1. 多阶段构建:构建阶段
FROM golang:1.17-alpine AS builder

# 2. 安装构建依赖
RUN apk add --no-cache git ca-certificates

# 3. 设置工作目录
WORKDIR /src

# 4. 复制Go模块文件
COPY go.mod go.sum ./

# 5. 下载依赖
RUN go mod download

# 6. 复制源代码
COPY . .

# 7. 构建应用(静态链接,减少依赖)
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o /app .

# 8. 多阶段构建:运行阶段
FROM scratch

# 9. 复制CA证书(用于HTTPS请求)
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/

# 10. 复制构建的可执行文件
COPY --from=builder /app /app

# 11. 设置环境变量
ENV PORT=8080

# 12. 声明暴露端口
EXPOSE 8080

# 13. 健康检查
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
    CMD ["/app", "healthcheck"]

# 14. 启动命令
CMD ["/app"]
  • 0. Go 微服务是用 Go 语言编写的、专注于单一业务功能的小型独立服务,通过 API 相互通信来共同构建完整应用。
  • 2. 安装依赖:

        1)apk = Alpine Linux的包管理器(类似Ubuntu的apt)【Alpine Linux是一个专为容器和嵌入式系统设计的超轻量Linux发行版】

        2)add --no-cache = 安装软件包但不保留缓存(减小镜像体积)

        3)git = 版本控制工具(用于克隆代码仓库)

        4)ca-certificates = SSL证书包(用于HTTPS安全连接)

  • 4. 模块文件

        1)go.mod:定义了项目需要哪些依赖包、依赖的版本要求、项目的基本信息

        2)go.sum:每个依赖包的哈希值

  • 5. go mod download:根据 go.mod 和 go.sum 文件下载所有项目依赖包到本地缓存。
  • 6. 这里也是先下载好了依赖,在复制的代码文件,这样的话,要是源代码变化,就可以不用重新下载依赖了
  • 7. 构建应用

        1)CGO_ENABLED=0:禁用CGO(纯go代码,不链接C库)

        2)GOOS=linux:编译为Linux可执行文件

        3)go build -a:-a 强制重新编译所有依赖

                go mod download只是下载了这些依赖,而go build是利用这些依赖去生成各种功能。可能在该虚拟机中之前使用过这些依赖,就会有缓存,系统就会直接用这些依赖,有可能使用的时候该依赖的版本和现在构造的系统不兼容,所以需要重新编译所有依赖包。

        4)-installsuffix cgo:使用独立的编译缓存(这里的编译缓存就是利用依赖生成的功能的缓存)使用独立编译缓存:每次构建都在该镜像的build阶段创建单独的缓存目录,运行阶段只复制产物。这里是linux_amd64_cgo/;不使用独立编译缓存:缓存可能持续影响后续构建,默认使用虚拟机中可能存在的旧缓存。

        5)-o /app:输出文件名为/app

        6).:编译当前目录的代码

        将当前目录的代码编译为linux可执行文件,在编译期间,不能使用C库,只能使用go语言的函数库,生成到/app中

  • 9. CA证书:就是第2步下载的ca-certificates

更多推荐