从会用 Docker 到会造 Docker:从零到企业级部署
第六章: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:
自动:
- 创建网络
- 拉镜像
- 创建容器
- 启动服务
后台启动:
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
↓
上线
更多推荐


所有评论(0)