第六章:Dockerfile(从会用 Docker 到会造 Docker)

docker基础
到这里,你已经掌握:

Image 镜像
    ↓
Container 容器
    ↓
Volume 数据
    ↓
Network 网络

但是现在你还是主要在用别人做好的镜像:

docker pull nginx
docker pull mysql
docker pull redis

真正开发工作中:

公司自己的项目怎么办?

比如:

你的项目:

商城系统
├── Java代码
├── 配置文件
├── 依赖
└── 启动脚本

怎么变成:

company-shop:v1

然后:

服务器:

docker run company-shop:v1

直接运行?

答案:

Dockerfile。


1. Dockerfile 是什么?

一句话:

Dockerfile 是制作 Docker 镜像的说明书。

比如做蛋糕:

普通人:

买蛋糕

Docker:

自己写配方
↓
制作蛋糕

Dockerfile:

就是配方。


例如:

Dockerfile:

FROM ubuntu

RUN apt update

RUN apt install nginx

COPY index.html /var/www/html/

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

意思:

从 Ubuntu 开始

安装 nginx

复制网页

启动 nginx

然后:

生成镜像:

my-web:v1

2. Dockerfile 工作流程

完整流程:

代码
 |
 |
 ↓

Dockerfile

 |
 |
 ↓

docker build

 |
 |
 ↓

Image 镜像

 |
 |
 ↓

docker run

 |
 |
 ↓

Container

3. 创建第一个 Dockerfile

准备目录:

my-nginx/

├── Dockerfile

└── index.html

index.html:

<h1>Hello Docker</h1>

Dockerfile:

FROM nginx

COPY index.html /usr/share/nginx/html/

解释:


FROM

基础镜像。

格式:

FROM 镜像名

例如:

FROM nginx

意思:

基于 nginx 制作。

类似:

站在别人肩膀上开发

COPY

复制文件。

格式:

COPY 本地文件 容器路径

例如:

COPY index.html /usr/share/nginx/html/

结果:

容器里面:

/usr/share/nginx/html/index.html

4. 构建镜像

进入目录:

cd my-nginx

执行:

docker build -t my-nginx:v1 .

解释:


build

创建镜像。


-t

tag。

例如:

-t my-nginx:v1

名字:

my-nginx

版本:

v1

.

当前目录。

Docker 会寻找:

./Dockerfile

构建过程:

你会看到:

Step 1/2

FROM nginx

Step 2/2

COPY index.html

成功:

Successfully built abc123

查看:

docker images

出现:

my-nginx

v1

5. 运行自己制作的镜像

启动:

docker run \
-d \
-p 8080:80 \
my-nginx:v1

访问:

localhost:8080

看到:

Hello Docker

成功。

你第一次造出了自己的镜像。


6. Dockerfile 常用指令大全

Dockerfile 最重要的几个:

FROM
RUN
COPY
ADD
WORKDIR
ENV
EXPOSE
CMD
ENTRYPOINT

下面逐个讲。


7. FROM

基础镜像。

必须第一行。

例如:

Python:

FROM python:3.12

Java:

FROM openjdk:17

Node:

FROM node:20

选择基础镜像:

开发:

ubuntu
debian

生产:

alpine
slim

例如:

推荐:

FROM python:3.12-slim

不要:

FROM ubuntu

然后自己安装 Python。

浪费空间。


8. RUN

执行 Linux 命令。

例如:

RUN apt update

安装:

RUN apt install -y nginx

例如:

FROM ubuntu

RUN apt update

RUN apt install -y curl

构建时:

执行。

不是运行容器时执行。


9. RUN 合并优化

错误:

RUN apt update

RUN apt install nginx

RUN apt clean

会产生很多层。

优化:

RUN apt update \
&& apt install -y nginx \
&& apt clean

减少镜像大小。


10. COPY

复制文件。

例如:

项目:

app/

├── Dockerfile

└── app.py

Dockerfile:

COPY app.py /app/

结果:

容器:

/app/app.py

11. WORKDIR

设置工作目录。

例如:

WORKDIR /app

之后:

COPY app.py .

等于:

COPY app.py /app/

推荐:

不要:

RUN cd /app

因为下一层失效。

使用:

WORKDIR /app

12. ENV

设置环境变量。

例如:

ENV PORT=8080

容器里面:

echo $PORT

输出:

8080

常见:

数据库:

MYSQL_ROOT_PASSWORD

程序:

JAVA_OPTS

13. EXPOSE

声明端口。

例如:

EXPOSE 8080

注意:

它不会真正打开端口。

真正:

需要:

-p

例如:

docker run -p 8080:8080 app

14. CMD(非常重要)

指定容器启动后执行什么。

例如:

CMD ["python","app.py"]

容器启动:

自动:

python app.py

例如:

Python项目:

Dockerfile:

FROM python:3.12

WORKDIR /app

COPY app.py .

CMD ["python","app.py"]

运行:

docker run my-python

自动:

python app.py

15. ENTRYPOINT

和 CMD 很像。

区别:

CMD:

容易被覆盖。

ENTRYPOINT:

固定执行。

例如:

ENTRYPOINT ["python"]

CMD ["app.py"]

运行:

docker run image

执行:

python app.py

运行:

docker run image test.py

执行:

python test.py

16. CMD 和 ENTRYPOINT 区别

记忆:

ENTRYPOINT
= 主程序

CMD
= 默认参数

例如:

ENTRYPOINT python

CMD app.py

组合:

python app.py

17. 一个真实 Python 项目 Dockerfile

项目:

my-api

├── app.py

├── requirements.txt

└── Dockerfile

requirements:

flask
requests

Dockerfile:

FROM python:3.12-slim

WORKDIR /app

COPY requirements.txt .

RUN pip install -r requirements.txt

COPY app.py .

EXPOSE 5000

CMD ["python","app.py"]

构建:

docker build -t my-api:v1 .

运行:

docker run \
-d \
-p 5000:5000 \
my-api:v1

18. 镜像分层和缓存(高手必须懂)

Dockerfile:

FROM python

COPY requirements.txt .

RUN pip install -r requirements.txt

COPY code .

为什么这样写?

因为:

Docker缓存。

第一次:

安装依赖
复制代码

第二次改代码:

Docker发现:

requirements没变。

所以:

不用重新安装。

速度快。


错误写法:

COPY . .

RUN pip install -r requirements.txt

每次代码变化:

重新安装依赖。

慢。


19. 多阶段构建(高级)

生产非常常见。

例如:

Java项目:

第一阶段:

编译:

JDK
+
源码
=
jar

第二阶段:

运行:

JRE
+
jar

结构:

阶段1

maven

↓

生成 jar

阶段2

jdk小镜像

↓

运行jar

优势:

镜像巨大减少。


20. 企业 Dockerfile 标准思路

通常:

1. 选择小基础镜像

2. 固定版本

3. 设置WORKDIR

4. 先复制依赖

5. 安装依赖

6. 再复制代码

7. 设置启动命令

8. 不使用root用户

21. 常见错误

错误1:

Dockerfile名字错误:

dockerfile

应该:

Dockerfile

大小写敏感。


错误2:

COPY路径错误

例如:

COPY app.py /app

但是:

文件不在当前目录。


错误3:

容器启动马上退出

原因:

CMD执行完结束。

例如:

错误:

CMD ["echo","hello"]

输出:

hello

然后容器退出。


本章核心命令

功能命令
构建镜像docker build
查看镜像docker images
查看构建历史docker history
删除镜像docker rmi
运行镜像docker run

第七章:Docker Compose(多容器项目管理神器)

到现在,你已经会:

✅ 拉镜像
✅ 创建容器
✅ 数据持久化
✅ 容器网络
✅ 制作自己的镜像

但是你会发现一个问题:

真实项目不是一个容器。

例如一个电商网站:

用户
              |
              ↓
          Nginx容器
              |
              ↓
         Java后端容器
              |
    -----------------
    |               |
    ↓               ↓
MySQL容器       Redis容器

如果不用 Compose,你可能需要:

docker run nginx ...

docker run java ...

docker run mysql ...

docker run redis ...

几十个参数。

非常痛苦。


Docker Compose 解决:

用一个配置文件,管理整个应用。


1. Docker Compose 是什么?

一句话:

Docker Compose 是用 YAML 文件描述多个 Docker 容器,然后一键启动、停止、管理整个系统。

以前:

docker run ...
docker run ...
docker run ...

现在:

docker compose up

全部启动。


2. Compose 的核心文件

名字:

docker-compose.yml

例如:

services:

  nginx:

  mysql:

  redis:

它描述:

  • 有哪些服务
  • 使用什么镜像
  • 端口
  • 网络
  • 数据卷
  • 环境变量

3. 第一个 Compose 示例

创建目录:

my-project/

└── docker-compose.yml

内容:

services:

  nginx:
    image: nginx
    ports:
      - "8080:80"

解释:


services

服务列表:

services:

下面每个:

就是一个容器。


nginx

服务名字:

nginx:

你自己定义。


image

使用哪个镜像:

image: nginx

等价:

docker run nginx

ports

端口:

ports:
  - "8080:80"

等价:

-p 8080:80

4. 启动 Compose

进入目录:

cd my-project

执行:

docker compose up

Docker:

自动:

  1. 创建网络
  2. 拉镜像
  3. 创建容器
  4. 启动服务

后台启动:

docker compose up -d

查看:

docker compose ps

类似:

NAME

my-project-nginx-1

STATUS

running

停止:

docker compose down

5. Compose 自动创建网络

以前:

我们需要:

docker network create app-net

Compose:

自动创建。

例如:

services:

  mysql:
    image: mysql

  backend:
    image: my-app

自动:

network:

my-project_default

两个容器自动加入。


6. Compose 实战:MySQL + Redis

完整例子:

services:

  mysql:
    image: mysql:8.0
    environment:
      MYSQL_ROOT_PASSWORD: 123456
    ports:
      - "3306:3306"

  redis:
    image: redis
    ports:
      - "6379:6379"

启动:

docker compose up -d

现在:

两个服务一起运行。


7. 数据卷 Volume + Compose

生产数据库必须保存数据。

修改:

services:

  mysql:

    image: mysql:8.0

    environment:
      MYSQL_ROOT_PASSWORD: 123456

    volumes:
      - mysql_data:/var/lib/mysql

volumes:

  mysql_data:

重点:

下面:

volumes:

  mysql_data:

表示:

创建 Docker Volume。

等价:

docker volume create mysql_data

8. 环境变量管理

不要:

直接写密码:

MYSQL_ROOT_PASSWORD: 123456

生产:

使用:

.env

例如:

项目:

project/

├── docker-compose.yml

└── .env

.env:

MYSQL_PASSWORD=123456

compose:

environment:

  MYSQL_ROOT_PASSWORD: ${MYSQL_PASSWORD}

启动时:

自动读取。


9. 完整项目案例

现在模拟真实网站:

结构:

shop/

├── docker-compose.yml

├── backend/

│    └── Dockerfile

└── nginx/

     └── nginx.conf

包含:

  • Nginx
  • 后端
  • MySQL
  • Redis

docker-compose.yml:

services:

  nginx:
    image: nginx
    ports:
      - "80:80"
    depends_on:
      - backend

  backend:
    build:
      ./backend
    depends_on:
      - mysql
      - redis

  mysql:
    image: mysql:8.0
    environment:
      MYSQL_ROOT_PASSWORD: 123456
    volumes:
      - mysql_data:/var/lib/mysql

  redis:
    image: redis

volumes:

  mysql_data:

启动:

docker compose up -d

一次启动:

nginx
 |
backend
 |
mysql
redis

10. depends_on 是什么?

例如:

backend:

 depends_on:

  - mysql

意思:

启动 backend 前:

先启动 mysql。

但是注意:

它不代表:

mysql 已经完全准备好。

例如:

MySQL启动需要10秒。

backend:

可能马上连接失败。

生产:

需要:

healthcheck。


11. healthcheck(生产技巧)

例如:

MySQL:

mysql:

  image: mysql:8.0

  healthcheck:

    test:
      [
       "CMD",
       "mysqladmin",
       "ping"
      ]

    interval: 10s

意思:

Docker 检查:

MySQL 是否真的可用。


12. build 自己的镜像

Compose 不只是 image。

可以:

backend:

  build:

    context: ./backend

意思:

读取:

backend/Dockerfile

自动构建。

等价:

docker build

13. image 和 build 区别

image

使用别人已有镜像:

image: mysql

类似:

docker pull mysql

build

自己制作:

build:
 ./app

类似:

docker build .

14. 查看日志

所有服务:

docker compose logs

实时:

docker compose logs -f

指定:

docker compose logs nginx

15. 重启服务

全部:

docker compose restart

指定:

docker compose restart backend

16. 进入 Compose 容器

例如:

进入 backend:

docker compose exec backend bash

类似:

docker exec -it backend bash

17. 更新代码后的流程

开发:

修改代码。

重新构建:

docker compose build

重新启动:

docker compose up -d

18. Compose 文件版本思维

以前:

version: "3"

现在:

新版 Docker Compose:

通常可以省略。

推荐:

services:

直接开始。


19. 企业真实部署流程

开发:

代码
 |
Dockerfile
 |
镜像
 |
docker-compose.yml

服务器:

git clone 项目

cd 项目

docker compose up -d

整个系统上线。


20. Compose 常用命令总结

功能命令
启动docker compose up
后台启动docker compose up -d
停止删除docker compose down
查看状态docker compose ps
查看日志docker compose logs
进入容器docker compose exec
重新构建docker compose build
重启docker compose restart

第八章:Docker 部署真实项目(从开发到上线)

前面你已经掌握 Docker 的核心技术:

镜像 Image
    ↓
容器 Container
    ↓
数据 Volume
    ↓
网络 Network
    ↓
Dockerfile
    ↓
Compose

现在进入真正工作场景:

一个项目如何从代码,变成线上运行的网站?

我们模拟一个真实互联网项目。


1. 一个真实网站的结构

假设我们开发一个商城:

技术栈:

前端:

Vue

后端:

Spring Boot

数据库:

MySQL

缓存:

Redis

入口:

Nginx

最终结构:

用户浏览器

                 |
                 |
                 ↓

            Nginx容器
        (80/443端口)

                 |
     ----------------------
     |                    |
     ↓                    ↓

Vue静态文件          Spring Boot

                          |
         ------------------
         |
         ↓

        MySQL

         |
         ↓

        Redis

2. 服务器准备

一般公司服务器:

Linux:

例如:

Ubuntu 22.04

安装:

Docker

Docker Compose

检查:

docker version

查看:

docker compose version

3. 项目目录设计(企业常见)

例如:

shop-system/

├── docker-compose.yml

├── nginx/

│   └── nginx.conf

├── backend/

│   ├── Dockerfile

│   └── app.jar

├── frontend/

│   ├── Dockerfile

│   └── dist/

└── mysql/

    └── init.sql

4. 部署后端 Spring Boot

假设:

已经打包:

app.jar

目录:

backend/

├── Dockerfile

└── app.jar

Dockerfile:

FROM eclipse-temurin:17-jdk

WORKDIR /app

COPY app.jar .

EXPOSE 8080

CMD ["java","-jar","app.jar"]

解释:


FROM

Java环境:

FROM eclipse-temurin:17-jdk

提供:

JDK17。


COPY

复制:

COPY app.jar .

进入:

/app/app.jar

CMD

启动:

CMD ["java","-jar","app.jar"]

构建:

docker build -t shop-backend:v1 .

测试:

docker run \
-p 8080:8080 \
shop-backend:v1

访问:

localhost:8080

5. 部署 Vue 前端

Vue 项目:

开发:

npm run build

生成:

dist/

里面:

index.html
assets/

Dockerfile:

FROM nginx

COPY dist/ /usr/share/nginx/html/

EXPOSE 80

构建:

docker build \
-t shop-frontend:v1 .

运行:

docker run \
-d \
-p 80:80 \
shop-frontend:v1

访问:

http://服务器IP

看到网页。


6. 为什么需要 Nginx?

很多新人疑惑:

Vue 可以直接运行?

为什么还需要 Nginx?

因为 Vue 打包后:

本质:

HTML

CSS

JS

图片

只是静态文件。

Nginx 擅长:

  • 提供静态文件
  • 反向代理
  • HTTPS
  • 负载均衡

7. Nginx 反向代理后端

用户访问:

/api/user

希望:

转给:

Spring Boot:8080

配置:

nginx.conf:

server {

    listen 80;

    location / {

        root /usr/share/nginx/html;

        index index.html;

    }

    location /api/ {

        proxy_pass http://backend:8080;

    }

}

重点:

proxy_pass

代理。


8. 使用 Compose 管理整个系统

最终:

docker-compose.yml:

services:

  nginx:

    image: nginx

    ports:

      - "80:80"

    volumes:

      - ./nginx/nginx.conf:/etc/nginx/nginx.conf

    depends_on:

      - backend

  backend:

    build:

      ./backend

    environment:

      DB_HOST: mysql

      REDIS_HOST: redis

    depends_on:

      - mysql

      - redis

  mysql:

    image: mysql:8.0

    environment:

      MYSQL_ROOT_PASSWORD: 123456

    volumes:

      - mysql_data:/var/lib/mysql

  redis:

    image: redis

volumes:

  mysql_data:

启动:

docker compose up -d

结果:

CONTAINER

nginx

backend

mysql

redis

全部启动。


9. 数据库连接为什么写 mysql?

注意:

Spring 配置:

以前:

spring.datasource.url=
jdbc:mysql://127.0.0.1:3306/shop

Docker:

错误。

应该:

jdbc:mysql://mysql:3306/shop

原因:

Docker 网络 DNS。

backend

  查询

mysql

  ↓

Docker DNS

  ↓

MySQL容器

10. 环境变量管理

生产不要:

写死密码。

错误:

MYSQL_ROOT_PASSWORD:123456

推荐:

.env

文件:

MYSQL_PASSWORD=xxxxxx
MYSQL_DATABASE=shop

compose:

environment:

 MYSQL_ROOT_PASSWORD:${MYSQL_PASSWORD}

11. 自动重启

服务器重启怎么办?

添加:

restart: always

例如:

backend:

 restart: always

效果:

服务器重启:

Docker自动启动服务。


12. 查看线上日志

网站打不开:

第一件事:

看日志。

Nginx:

docker compose logs nginx

后端:

docker compose logs backend

实时:

docker compose logs -f backend

13. 进入线上容器排查

例如:

后端:

docker compose exec backend bash

检查:

ls

环境:

env

网络:

ping mysql

14. 更新版本怎么做?

比如:

代码修改。

流程:

1. 拉代码

git pull

2. 重新构建

docker compose build

3. 重启

docker compose up -d

完成升级。


15. 零停机部署(进阶)

大公司:

不会直接:

停止旧版本

启动新版本

因为会中断。

使用:

蓝绿部署:

Nginx

           |

    ----------------

    |              |

 v1容器         v2容器

旧版本          新版本

测试 v2:

成功:

切换流量。


16. Docker 日志管理

默认:

日志存在:

/var/lib/docker/containers/

长期运行会爆。

配置:

限制大小:

{
 "log-driver":"json-file",
 "log-opts":{
   "max-size":"10m",
   "max-file":"3"
 }
}

生产必须做。


17. Docker 安全基础

不要:

直接 root。

Dockerfile:

错误:

USER root

推荐:

创建用户:

RUN useradd app

USER app

不要:

随便暴露端口。

例如:

数据库:

3306

不应该开放公网。


18. Docker 生产检查清单

上线前:

镜像

✅ 固定版本

不要:

latest

数据

✅ Volume

数据库必须持久化。


网络

✅ 自定义 network


密码

✅ 环境变量


日志

✅ 限制大小


重启

✅ restart


安全

✅ 非 root


19. 一个真实服务器上线流程

公司常见:

开发电脑

↓

提交 Git

↓

CI/CD 自动构建

↓

Docker build

↓

推送镜像仓库

↓

服务器 pull 镜像

↓

docker compose up -d

↓

上线

更多推荐