Docker容器化部署完整教程:一次构建到处运行
我以前部署项目特别痛苦,在本地跑得好好的,到了服务器就报错,环境不一致的问题折磨死人。装数据库、配依赖、改配置,一台服务器搞半天。后来用了Docker,把应用和环境打包成镜像,到哪都能跑,部署从半天变几分钟。今天把Docker从入门到实战的方法分享出来。
什么是Docker
Docker是容器化工具,把应用和依赖打包成容器,到处运行。
跟虚拟机的区别:虚拟机模拟整个操作系统,笨重。Docker共享主机内核,轻量,启动快,占用少。
Docker的好处:
1. 环境一致:本地和服务器环境一样,不会"在我电脑上能跑"。
2. 快速部署:拉镜像启动容器,几分钟搞定。
3. 资源隔离:每个容器独立,互不影响。
4. 易于扩展:需要多实例就多启动几个容器。
5. 版本管理:镜像有版本,回退方便。
我现在所有项目都用Docker部署,再也不用在服务器上装环境了。
安装Docker
Windows:下载Docker Desktop(docker.com),安装。需要开启WSL2。安装后启动Docker Desktop,右下角图标变绿就行。
Mac:同样下载Docker Desktop,安装。M1/M2芯片选Apple Silicon版本。
Linux(Ubuntu):
sudo apt update
sudo apt install docker.io
sudo systemctl start docker
sudo systemctl enable docker
把当前用户加到docker组,免sudo:sudo usermod -aG docker $USER。重新登录生效。
验证:docker --version和docker run hello-world。能看到Hello from Docker就行。
我Windows用Docker Desktop开发,Linux服务器装Docker CE部署。
核心概念
三个核心概念:
镜像(Image):只读模板,包含应用和环境。类似安装光盘。比如nginx:latest就是一个nginx镜像。
容器(Container):镜像运行起来的实例。类似用光盘装好的系统。一个镜像可以启动多个容器。
仓库(Registry):存镜像的地方。Docker Hub是官方仓库(类似应用商店)。私有仓库有Harbor等。
关系:从仓库拉镜像 → 用镜像启动容器 → 容器里跑应用。
镜像操作
搜索镜像:docker search nginx。搜Docker Hub上的镜像。
拉取镜像:docker pull nginx。默认拉latest版本。指定版本:docker pull nginx:1.25。
查看本地镜像:docker images。或docker image ls。
删除镜像:docker rmi 镜像ID。或docker image rm 镜像名。
给镜像打标签:docker tag nginx:latest mynginx:v1。
导出镜像:docker save -o nginx.tar nginx。导入:docker load -i nginx.tar。没网的环境用。
我常用镜像:nginx(Web服务器)、mysql(数据库)、redis(缓存)、node(Node.js环境)、python(Python环境)。
容器操作
启动容器:docker run [参数] 镜像名 [命令]
常用参数:
-d:后台运行。
-p 8080:80:端口映射,主机8080映射到容器80。
-v /host:/container:目录挂载,主机目录映射到容器。
-e KEY=VALUE:环境变量。
--name myapp:容器命名。
--restart always:自动重启。
--network mynet:加入网络。
例子:docker run -d -p 8080:80 --name mynginx nginx。启动nginx,访问localhost:8080就能看到nginx欢迎页。
查看运行中的容器:docker ps。看所有容器(包括停止的):docker ps -a。
启动/停止/重启容器:docker start 容器名、docker stop 容器名、docker restart 容器名。
删除容器:docker rm 容器名。运行中的容器加-f强制删除。
进入容器:docker exec -it 容器名 bash。在容器里执行命令,像SSH一样。-it是交互式终端。
查看日志:docker logs 容器名。加-f实时查看(类似tail -f)。--tail 100看最后100行。
查看容器详情:docker inspect 容器名。看IP、挂载、环境变量等。
查看容器资源占用:docker stats。看CPU、内存、网络。
在容器里执行命令:docker exec 容器名 ls /。不进入容器执行命令。
拷贝文件:docker cp 文件 容器名:/路径。从主机拷到容器。反过来也行。
我调试容器常用docker exec -it 容器名 bash进去看,或者docker logs看日志。
Dockerfile编写
Dockerfile是构建镜像的脚本,告诉Docker怎么打包应用。
常用指令:
FROM:基础镜像。FROM node:18-alpine。
WORKDIR:工作目录。WORKDIR /app。
COPY:复制文件。COPY . .(复制当前目录所有文件到容器)。
RUN:构建时执行命令。RUN npm install。
ENV:环境变量。ENV NODE_ENV=production。
EXPOSE:声明端口。EXPOSE 3000。
CMD:容器启动时执行的命令。CMD ["node", "app.js"]。
ENTRYPOINT:类似CMD但更固定,配合CMD用。
VOLUME:声明挂载点。VOLUME /data。
ARG:构建参数。ARG VERSION=1.0。
一个Node.js应用的Dockerfile例子:
FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install --production
COPY . .
EXPOSE 3000
CMD ["node", "app.js"]
构建镜像:docker build -t myapp:v1 .。-t指定名字和标签,.表示当前目录(Dockerfile所在目录)。
构建优化技巧:
1. 用alpine基础镜像,体积小。
2. 先COPY package.json再npm install,最后COPY代码。利用缓存,代码变了不用重新装依赖。
3. 用.dockerignore排除不需要的文件(node_modules、.git等)。
4. 多阶段构建,减小最终镜像体积。
多阶段构建例子:
阶段1:构建
FROM node:18 AS builder
WORKDIR /app
COPY . .
RUN npm install && npm run build
阶段2:运行
FROM nginx:alpine
COPY --from=builder /app/dist /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
最终镜像只有nginx和编译产物,很小。我前端项目都用多阶段构建,镜像从1G降到50M。
数据持久化
容器删除后数据没了,要持久化数据。
方法一:挂载主机目录(bind mount)
docker run -v /data/mysql:/var/lib/mysql mysql。主机/data/mysql映射到容器的数据库目录。容器删了数据还在。
方法二:数据卷(volume)
docker volume create mydata。创建数据卷。docker run -v mydata:/var/lib/mysql mysql。Docker管理数据卷,比bind mount更推荐。
方法三:挂载文件
docker run -v /host/config.conf:/etc/config.conf myapp。挂载配置文件。
我数据库容器一定挂载数据卷,不然容器删了数据全丢。
网络
容器之间通信要配网络。
查看网络:docker network ls。
创建网络:docker network create mynet。
容器加入网络:docker run --network mynet --name app myapp。容器间用容器名访问,比如app容器访问数据库:mysql:3306(mysql是容器名)。
bridge(默认):容器通过网桥通信。
host:容器使用主机网络,没有端口映射。
none:没有网络。
我Web应用和数据库放同一个自定义网络,用容器名通信,不用IP。
Docker Compose
多个容器一起管理用Docker Compose,一个yaml文件定义所有服务。
安装:Docker Desktop自带。Linux单独装docker-compose或用docker compose(新版内置)。
docker-compose.yml例子(Web+数据库+缓存):
version: "3.8"
services:
web:
build: .
ports:
- "3000:3000"
depends_on:
- db
- redis
environment:
- DB_HOST=db
- REDIS_HOST=redis
db:
image: mysql:8
environment:
- MYSQL_ROOT_PASSWORD=123456
- MYSQL_DATABASE=myapp
volumes:
- dbdata:/var/lib/mysql
redis:
image: redis:7-alpine
volumes:
- redisdata:/data
volumes:
dbdata:
redisdata:
启动所有服务:docker-compose up -d。-d后台运行。
停止:docker-compose down。加-v删数据卷。
查看状态:docker-compose ps。
查看日志:docker-compose logs -f。
重新构建:docker-compose up -d --build。
Docker Compose太方便了,一个命令启动整个项目环境。我每个项目都有docker-compose.yml,一键部署。
常用应用部署
部署MySQL:
docker run -d --name mysql -p 3306:3306 -e MYSQL_ROOT_PASSWORD=密码 -v mysql_data:/var/lib/mysql mysql:8
部署Redis:
docker run -d --name redis -p 6379:6379 -v redis_data:/data redis:7-alpine
部署Nginx:
docker run -d --name nginx -p 80:80 -p 443:443 -v /html:/usr/share/nginx/html -v /nginx.conf:/etc/nginx/nginx.conf nginx
部署WordPress:
docker run -d --name wp -p 8080:80 -e WORDPRESS_DB_HOST=mysql -e WORDPRESS_DB_PASSWORD=密码 wordpress
我常用应用都做成Compose文件,换服务器一键启动。
镜像加速
国内拉Docker Hub镜像慢,配加速。
编辑/etc/docker/daemon.json(Linux)或Docker Desktop设置里配:
{"registry-mirrors": ["https://镜 像加速地址"]}
阿里云、腾讯云都有免费加速地址。配完重启Docker。
我配了阿里云加速,拉镜像速度快了十倍。
安全注意事项
1. 别用root用户跑容器,创建普通用户。
2. 别把敏感信息写死在Dockerfile,用环境变量或secrets。
3. 定期更新基础镜像,修复漏洞。
4. 用非官方镜像要谨慎,可能有后门。
5. 别把.dockerignore忘了,别把密钥打包进镜像。
6. 容器端口别全开放,只开需要的。
常见问题
问题1:容器启动就退出
原因:前台没有持续运行的进程。解决:确保CMD/ENTRYPOINT启动的是前台进程。比如nginx用nginx -g "daemon off;"而不是nginx。
问题2:端口被占用
解决:换端口,或者停掉占用的程序。docker ps看是不是有旧容器占着。
问题3:磁盘空间不足
解决:docker system prune清理无用镜像、容器、网络。docker system df看占用。
问题4:构建缓存失效很慢
解决:把变化少的放前面(如COPY package.json + npm install),变化多的放后面(COPY代码)。
问题5:容器连不上数据库
解决:检查是否在同一网络,用容器名访问不是localhost。
我的Docker工作流
分享我的Docker使用流程:
1. 项目根目录写Dockerfile。
2. 写docker-compose.yml,定义应用、数据库、缓存等服务。
3. 本地docker-compose up -d开发测试。
4. 测试好push镜像到仓库(Docker Hub或私有仓库)。
5. 服务器pull镜像,docker-compose up -d部署。
6. 更新时重新build push,服务器pull restart。
这套流程用了两年,部署效率提升十倍。以前搞半天环境,现在几分钟。
总结
Docker是现代开发的必备工具,核心概念就三个:镜像、容器、仓库。常用命令也不多:pull、run、ps、stop、build、exec、logs。把这些用熟,日常开发部署够了。Docker Compose管理多容器,一键启动整个环境。学Docker投资回报率极高,早学早受益。
