[Docker] dockerfile实战:构建一个属于自己的Nginx镜像

DeepSeek生成(2025年10月28日22:41:17)

Docker 打包 Nginx 完整教学

Docker 基础概念

什么是 Docker?

Docker 是一个开源的应用容器引擎,可以让开发者打包他们的应用以及依赖包到一个可移植的容器中。

核心概念:

  • 镜像(Image):类似于虚拟机的快照,包含运行应用所需的所有内容
  • 容器(Container):镜像的运行实例
  • Dockerfile:用于构建镜像的脚本文件
  • 仓库(Registry):存放镜像的地方,如 Docker Hub

Nginx 简介

Nginx 是一个高性能的 HTTP 和反向代理服务器,常用于:

  • 静态网站服务
  • 负载均衡
  • API 网关
  • 反向代理

Dockerfile 详解

Dockerfile 基本结构

Dockerfile 是由一系列指令和参数构成的文本文件,每条指令都会在镜像上创建一个新的层。

常用指令:

  • FROM:指定基础镜像
  • RUN:执行命令
  • COPY:复制文件
  • ADD:复制文件(功能更强大)
  • EXPOSE:声明端口
  • CMD:容器启动命令
  • ENTRYPOINT:容器入口点
  • ENV:设置环境变量
  • WORKDIR:设置工作目录

实战:创建 Nginx Docker 镜像

基础版本 Dockerfile

让我们从最简单的 Nginx Dockerfile 开始:

# 使用官方 Nginx 镜像作为基础
FROM nginx:latest

# 维护者信息(可选)
LABEL maintainer="your-email@example.com"

# 将本地的静态文件复制到容器中的 Nginx 默认目录
COPY ./html /usr/share/nginx/html

# 暴露 80 端口
EXPOSE 80

# 启动 Nginx(基础镜像已包含,此处可省略)
CMD ["nginx", "-g", "daemon off;"]

详细解释:

  1. FROM nginx:latest

    • 使用官方 Nginx 镜像作为基础
    • latest 标签表示使用最新版本
  2. COPY ./html /usr/share/nginx/html

    • 将本地 html 目录复制到容器的 Nginx 默认网站目录
    • 你需要提前准备好静态文件
  3. EXPOSE 80

    • 声明容器运行时监听的端口
    • 这只是声明,实际映射需要在运行容器时指定
  4. CMD ["nginx", "-g", "daemon off;"]

    • 容器启动时执行的命令
    • daemon off 让 Nginx 在前台运行(Docker 要求)

进阶版本 Dockerfile

# 使用特定版本的 Nginx,提高稳定性
FROM nginx:1.23-alpine

# 设置维护者信息
LABEL maintainer="your-name@example.com"
LABEL description="Custom Nginx Docker Image"

# 设置环境变量
ENV NGINX_PORT=80
ENV NGINX_ROOT=/usr/share/nginx/html

# 安装必要的工具(Alpine Linux 使用 apk)
RUN apk update && apk add --no-cache \
    curl \
    vim

# 创建自定义配置目录
RUN mkdir -p /etc/nginx/conf.d/custom

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

# 复制网站文件
COPY html/ /usr/share/nginx/html/

# 设置权限
RUN chown -R nginx:nginx /usr/share/nginx/html
RUN chmod -R 755 /usr/share/nginx/html

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

# 暴露端口
EXPOSE ${NGINX_PORT}

# 启动 Nginx
CMD ["nginx", "-g", "daemon off;"]

构建和运行

项目结构准备

创建以下目录结构:

nginx-docker/
├── Dockerfile
├── nginx.conf
├── default.conf
└── html/
    ├── index.html
    └── style.css

创建配置文件

nginx.conf (基础版本):

user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;

events {
    worker_connections 1024;
}

http {
    include /etc/nginx/mime.types;
    default_type application/octet-stream;
    
    log_format main '$remote_addr - $remote_user [$time_local] "$request" '
                    '$status $body_bytes_sent "$http_referer" '
                    '"$http_user_agent" "$http_x_forwarded_for"';
    
    access_log /var/log/nginx/access.log main;
    
    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    keepalive_timeout 65;
    types_hash_max_size 2048;
    
    include /etc/nginx/conf.d/*.conf;
}

default.conf:

server {
    listen 80;
    server_name localhost;
    
    location / {
        root /usr/share/nginx/html;
        index index.html index.htm;
        try_files $uri $uri/ =404;
    }
    
    # 健康检查端点
    location /health {
        access_log off;
        return 200 "healthy\n";
        add_header Content-Type text/plain;
    }
    
    # 禁止访问隐藏文件
    location ~ /\. {
        deny all;
        access_log off;
        log_not_found off;
    }
    
    error_page 500 502 503 504 /50x.html;
    location = /50x.html {
        root /usr/share/nginx/html;
    }
}

html/index.html:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>我的 Nginx Docker 网站</title>
    <link rel="stylesheet" href="style.css">
</head>
<body>
    <div class="container">
        <h1>🚀 欢迎使用 Nginx Docker!</h1>
        <p>这是一个运行在 Docker 容器中的 Nginx 服务器</p>
        <div class="info">
            <p><strong>服务器:</strong> Nginx</p>
            <p><strong>容器平台:</strong> Docker</p>
            <p><strong>状态:</strong> <span class="status">运行中</span></p>
        </div>
    </div>
</body>
</html>

html/style.css:

* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

body {
    font-family: 'Arial', sans-serif;
    background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
    min-height: 100vh;
    display: flex;
    align-items: center;
    justify-content: center;
}

.container {
    background: white;
    padding: 3rem;
    border-radius: 15px;
    box-shadow: 0 10px 30px rgba(0,0,0,0.2);
    text-align: center;
    max-width: 500px;
}

h1 {
    color: #333;
    margin-bottom: 1rem;
}

p {
    color: #666;
    line-height: 1.6;
    margin-bottom: 1rem;
}

.info {
    background: #f8f9fa;
    padding: 1.5rem;
    border-radius: 8px;
    margin-top: 1.5rem;
}

.status {
    color: #28a745;
    font-weight: bold;
}

构建镜像

在项目根目录执行:

# 构建镜像
docker build -t my-nginx .

# 查看构建的镜像
docker images

构建过程详解:

  1. Docker 读取 Dockerfile
  2. 下载基础镜像(如果本地没有)
  3. 按顺序执行每条指令
  4. 为每个指令创建新的镜像层
  5. 最终生成完整的镜像

运行容器

# 运行基础版本
docker run -d -p 8080:80 --name my-nginx-container my-nginx

# 运行进阶版本(带健康检查)
docker run -d \
  -p 8080:80 \
  --name my-nginx-container \
  --health-cmd "curl -f http://localhost/health || exit 1" \
  --health-interval=30s \
  my-nginx

参数解释:

  • -d:后台运行
  • -p 8080:80:端口映射(主机端口:容器端口)
  • --name:容器名称

验证运行

# 查看运行中的容器
docker ps

# 查看容器日志
docker logs my-nginx-container

# 检查容器健康状态
docker inspect --format='{{.State.Health.Status}}' my-nginx-container

# 访问网站(在浏览器中打开)
# http://localhost:8080

高级配置

使用环境变量

创建支持环境变量的 Dockerfile:

FROM nginx:1.23-alpine

# 设置环境变量默认值
ENV NGINX_PORT=80
ENV NGINX_HOST=localhost
ENV NGINX_ROOT=/usr/share/nginx/html

# 复制可配置的 Nginx 配置模板
COPY nginx.conf.template /etc/nginx/nginx.conf.template
COPY start-nginx.sh /usr/local/bin/

# 安装 envsubst 用于模板替换
RUN apk add --no-cache gettext

# 设置启动脚本权限
RUN chmod +x /usr/local/bin/start-nginx.sh

# 复制静态文件
COPY html/ /usr/share/nginx/html/

EXPOSE ${NGINX_PORT}

# 使用启动脚本
CMD ["/usr/local/bin/start-nginx.sh"]

start-nginx.sh:

#!/bin/sh

# 使用 envsubst 替换环境变量
envsubst < /etc/nginx/nginx.conf.template > /etc/nginx/nginx.conf

# 启动 Nginx
exec nginx -g 'daemon off;'

运行带环境变量的容器:

docker run -d \
  -p 8080:80 \
  -e NGINX_PORT=80 \
  -e NGINX_HOST=localhost \
  --name my-nginx \
  my-nginx

使用多阶段构建

# 构建阶段
FROM node:16-alpine as build-stage

WORKDIR /app

# 复制 package.json 并安装依赖
COPY package*.json ./
RUN npm install

# 复制源码并构建
COPY . .
RUN npm run build

# 生产阶段
FROM nginx:1.23-alpine as production-stage

# 复制构建产物到 Nginx
COPY --from=build-stage /app/dist /usr/share/nginx/html

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

EXPOSE 80

CMD ["nginx", "-g", "daemon off;"]

最佳实践

1. 安全性

# 使用非 root 用户
FROM nginx:1.23-alpine

# 创建非 root 用户(如果基础镜像没有)
RUN addgroup -g 1000 -S nginx-user && \
    adduser -S -D -H -u 1000 -h /var/cache/nginx -s /sbin/nologin -G nginx-user -g nginx-user nginx-user

# 更改文件所有权
RUN chown -R nginx-user:nginx-user /usr/share/nginx/html

# 使用非 root 用户运行
USER nginx-user

2. 优化镜像大小

# 使用 Alpine Linux 版本
FROM nginx:1.23-alpine

# 清理缓存
RUN apk update && apk upgrade && \
    rm -rf /var/cache/apk/*

# 使用多阶段构建减少最终镜像大小

3. 性能优化

FROM nginx:1.23-alpine

# 优化 Nginx 配置
RUN echo "worker_processes auto;" > /etc/nginx/nginx.conf && \
    echo "events { worker_connections 1024; }" >> /etc/nginx/nginx.conf && \
    echo "http { include /etc/nginx/mime.types; default_type application/octet-stream; sendfile on; tcp_nopush on; keepalive_timeout 65; include /etc/nginx/conf.d/*.conf; }" >> /etc/nginx/nginx.conf

常用命令备忘

# 构建镜像
docker build -t my-nginx .

# 运行容器
docker run -d -p 8080:80 --name nginx-container my-nginx

# 查看日志
docker logs nginx-container

# 进入容器
docker exec -it nginx-container sh

# 停止容器
docker stop nginx-container

# 删除容器
docker rm nginx-container

# 删除镜像
docker rmi my-nginx

# 查看资源使用
docker stats nginx-container

# 保存镜像到文件
docker save -o my-nginx.tar my-nginx

# 从文件加载镜像
docker load -i my-nginx.tar

故障排除

常见问题及解决方案:

  1. 端口被占用

    # 查看端口占用
    netstat -tulpn | grep 8080
    # 或者使用其他端口
    docker run -d -p 8081:80 --name nginx-container my-nginx
    
  2. 权限问题

    # 在 Dockerfile 中确保文件权限正确
    RUN chmod -R 755 /usr/share/nginx/html
    
  3. 配置文件错误

    # 检查 Nginx 配置
    docker exec nginx-container nginx -t
    
  4. 容器启动失败

    # 查看详细日志
    docker logs nginx-container
    

总结

通过这个完整的学习文档,你应该已经掌握了:

  • ✅ Docker 和 Nginx 的基本概念
  • ✅ Dockerfile 的编写和理解
  • ✅ 如何构建自定义 Nginx 镜像
  • ✅ 容器的运行和管理
  • ✅ 高级配置和最佳实践
posted on 2025-10-28 22:53  风惊庭前叶  阅读(29)  评论(0)    收藏  举报