一、什么是 Docker?为什么要学它?
想象一下这个场景:你在本地写好的代码跑得顺顺当当,推到服务器上就各种报错------"在我电脑上明明是好的啊!"这话是不是特别耳熟?
Docker 就是来解决这个问题的。它是一个开源的容器化平台,能把你写的应用程序和它所依赖的一切(代码、运行时、系统工具、库等)打包成一个独立的容器,实现"一次构建,到处运行"。
与传统虚拟机相比,Docker 容器有三大核心优势:
-
轻量高效:容器共享宿主机内核,启动速度是毫秒级,单台机器可以同时运行数百个容器。
-
环境一致:开发、测试、生产环境完全统一,部署故障率可下降 80%以上。
-
快速部署:秒级启动容器,配合 CI/CD 流程,构建到部署周期从几十分钟缩短到几分钟。
听起来不错吧?别急,咱们先从三个最核心的概念入手。
二、核心概念:镜像、容器、仓库
要搞懂 Docker,记住三个词就够了:镜像、容器、仓库。
1. 镜像(Image)------ 应用的"安装包"
镜像是一个只读的模板,里面打包了运行一个应用所需要的全部东西。
打个比方 :镜像就像一张食谱,纸上写好了需要什么材料、怎么做,但食谱本身不能吃。你要想吃上这道菜,还得照着食谱实际操作一番。
查看本地镜像用 docker images,拉取镜像用 docker pull nginx。
2. 容器(Container)------ 运行起来的"实例"
容器是镜像的运行实例。照着食谱做出来的那道菜,就是容器。
你可以照着同一张食谱做出一盘、两盘、十盘菜,每一盘都是独立的,吃光这一盘,不影响那一盘。容器也一样,基于同一个镜像可以启动任意多个独立的容器实例。
常用命令:
-
docker run -d -p 80:80 --name my-nginx nginx:运行容器 -
docker ps:查看运行中的容器 -
docker stop my-nginx:停止容器 -
docker rm my-nginx:删除容器
3. 仓库(Repository)------ 镜像的"应用商店"
仓库是专门存放镜像的地方。Docker Hub 是官方公共仓库,里面有海量的现成镜像可以直接用,像 MySQL、Redis、Nginx 这些,一条命令就能拉下来。
继续用做菜打比方:你想做番茄炒蛋但手头没有食谱,那就去超市(仓库)买一本。超市里什么食谱都有。
三者协作关系 :docker pull 从仓库把镜像拉下来 → docker build 构建自己的镜像 → docker push 把镜像推到仓库分享给别人 → docker run 启动容器。
三、Docker 安装
系统要求
-
64 位系统,CPU 支持虚拟化
-
Linux 内核 ≥ 3.10
-
最低配置:2GB 内存 + 20GB 磁盘空间
Linux(Ubuntu)安装
bash
# 更新包索引
sudo apt-get update
# 安装依赖
sudo apt-get install apt-transport-https ca-certificates curl software-properties-common
# 添加 Docker 官方 GPG 密钥
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
# 添加稳定版仓库
sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
# 安装 Docker Engine
sudo apt-get update
sudo apt-get install docker-ce
# 验证安装
docker --version
docker run hello-world
Windows / macOS
访问 Docker Desktop 官网,下载对应安装包,双击按照向导安装即可。安装完成后启动 Docker Desktop。
国内用户配置镜像加速
国内访问 Docker Hub 可能比较慢,可以配置国内镜像加速器:
bash
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["https://registry.docker-cn.com"]
}
EOF
sudo systemctl restart docker
四、常用命令速查
镜像管理
| 命令 | 作用 |
|---|---|
docker pull nginx:latest |
拉取镜像 |
docker images |
查看本地镜像列表 |
docker rmi <镜像ID> |
删除镜像 |
docker build -t myapp:1.0 . |
从 Dockerfile 构建镜像 |
容器操作
| 命令 | 作用 |
|---|---|
docker run -d -p 8080:80 --name web nginx |
后台运行容器 |
docker ps |
查看运行中的容器 |
docker ps -a |
查看所有容器(含已停止) |
docker exec -it web /bin/bash |
进入容器终端 |
docker logs web |
查看容器日志 |
docker stop web |
停止容器 |
docker rm web |
删除容器 |
五、第一个实战:用 Docker 跑一个网页
我们来跑一个真正的 Nginx 网页服务器,这是最经典的入门案例:
bash
# 拉取 Nginx 镜像
docker pull nginx:latest
# 运行容器,把宿主机的 8080 端口映射到容器的 80 端口
docker run -d -p 8080:80 --name my-nginx nginx
# 验证是否启动成功
curl http://127.0.0.1:8080
如果看到 Nginx 的欢迎页面,你就成功了!
如果想把自己写的静态网页放进去,可以用数据卷挂载:
bash
docker run -d -p 8080:80 -v /my-web:/usr/share/nginx/html --name my-site nginx
这样只要修改你本地的 /my-web 目录下的文件,容器里的网页就会实时更新。
六、Dockerfile:定制自己的镜像
预置的镜像不够用怎么办?自己写一个 Dockerfile 来定制。
Dockerfile 是一个文本文件,里面写明了镜像构建的每一步。
常用指令速查
| 指令 | 作用 | 示例 |
|---|---|---|
FROM |
指定基础镜像 | FROM python:3.11-slim |
WORKDIR |
设置工作目录 | WORKDIR /app |
COPY |
复制文件到镜像 | COPY . . |
RUN |
执行构建命令 | RUN pip install -r requirements.txt |
ENV |
设置环境变量 | ENV NODE_ENV=production |
EXPOSE |
声明端口 | EXPOSE 80 |
CMD |
启动命令 | CMD ["python", "app.py"] |
完整案例:Python 应用
创建一个 Dockerfile:
dockerfile
FROM python:3.11-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
EXPOSE 5000
CMD ["python", "app.py"]
然后在同目录下执行:
bash
docker build -t my-python-app .
docker run -d -p 5000:5000 my-python-app
几个小技巧
-
多用 .dockerignore :像写
.gitignore一样,把node_modules/、*.log这些无关文件排除掉,构建速度会快很多。 -
合并 RUN 指令 :
RUN apt-get update && apt-get install -y curl比分开写要好,因为每一条RUN都会产生一个新的镜像层,合并能减少体积。 -
多阶段构建:适合编译型语言,把编译环境和运行环境分开,最终的镜像体积能小几十倍。
七、Docker Compose:管理多个容器
一个应用往往需要多个服务配合:前端、后端、数据库、缓存......一个个手动启动太麻烦了。Docker Compose 就是用来解决这个问题的。
使用三步走
-
编写 Dockerfile 定义各个服务
-
编写
docker-compose.yml编排所有服务 -
执行
docker-compose up一键启动所有服务
实战案例:WordPress + MySQL
yaml
version: '3.8'
services:
wordpress:
image: wordpress:latest
ports:
- "8080:80"
environment:
WORDPRESS_DB_HOST: db
WORDPRESS_DB_PASSWORD: example
networks:
- mynet
db:
image: mysql:5.7
environment:
MYSQL_ROOT_PASSWORD: example
volumes:
- db_data:/var/lib/mysql
networks:
- mynet
volumes:
db_data:
networks:
mynet:
启动:docker-compose up -d
停止并清理:docker-compose down
所有服务在一个配置文件里定义,一条命令全部搞定------这就是 Compose 的魅力。
八、搭建自己的小项目:完整案例
我们来做一个真正"能用得上的"小工具------一个带有管理面板的静态文件服务。
需求:你想把自己电脑上某个文件夹里的静态文件(网页、图片等)对外提供服务,同时需要一个简单的管理面板来查看访问统计。
实现方案:用 Nginx 提供静态文件服务,用 Redis 存储访问计数,用 Python 写一个轻量的统计接口。
目录结构如下:
text
my-webapp/
├── docker-compose.yml
├── nginx/
│ └── default.conf
├── html/
│ └── index.html
└── app/
├── Dockerfile
└── app.py
步骤 1:写一个简单的统计接口
创建 app/app.py:
python
from flask import Flask, jsonify
import redis
import os
app = Flask(__name__)
r = redis.Redis(host='redis', port=6379, decode_responses=True)
@app.route('/stats')
def stats():
count = r.get('page_views')
return jsonify({'views': int(count) if count else 0})
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000)
步骤 2:写 Flask 服务的 Dockerfile
创建 app/Dockerfile:
dockerfile
FROM python:3.11-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install flask redis
COPY . .
CMD ["python", "app.py"]
步骤 3:配置 Nginx 反向代理
创建 nginx/default.conf:
text
server {
listen 80;
server_name localhost;
location / {
root /usr/share/nginx/html;
index index.html;
}
location /api/ {
proxy_pass http://flask-app:5000/;
proxy_set_header Host $host;
}
}
步骤 4:编写 docker-compose.yml:
yaml
version: '3.8'
services:
nginx:
image: nginx:alpine
ports:
- "8080:80"
volumes:
- ./nginx/default.conf:/etc/nginx/conf.d/default.conf
- ./html:/usr/share/nginx/html
depends_on:
- flask-app
flask-app:
build: ./app
depends_on:
- redis
redis:
image: redis:alpine
步骤 5:启动
bash
docker-compose up -d
启动后,访问 http://localhost:8080 可以看到静态页面,访问 http://localhost:8080/api/stats 可以看到访问统计。所有服务在后台稳定运行,互不干扰,随时可以一键停止全部清理。
是不是很有成就感?这就是 Docker 的魅力------简单、干净、可控。
九、常见问题与避坑指南
Q1:docker run -d 后容器马上就停了?
容器必须有一个前台进程在跑,后台模式启动的容器如果没有持续运行的进程,Docker 会认为它完成了任务然后自动停止。解决办法:确保容器里有 nginx、mysql 这类长期运行的进程。
Q2:国内 pull 镜像特别慢?
配置镜像加速器。阿里云、中科大、网易都提供了免费加速服务。修改
/etc/docker/daemon.json添加镜像地址后重启 docker。
Q3:端口被占用了怎么办?
改映射端口。比如
-p 8081:80把容器 80 端口映射到主机的 8081 端口。
Q4:容器删了数据也没了?
容器的数据默认是临时的,需要持久化就用数据卷挂载,比如
-v /host/path:/container/path。
十、写在最后
Docker 的学习曲线并不陡,今天你读完了这篇文章,就已经迈出了第一步。
建议的学习路径:
-
先跑几个简单的容器(nginx、redis)感受一下
-
动手写一个 Dockerfile,把自己的应用打包成镜像
-
用 docker-compose 把前端、后端、数据库串起来
云原生时代,容器化技术已经成为开发者的必修课。希望这份指南能帮你迈出第一步,把"环境差异"这个老大难问题彻底甩在身后。后续可以进一步了解 Kubernetes(K8s)、CI/CD 流水线等进阶内容,开启你的云原生之旅。