从零搭建 Docker 自动化工作流:开发、测试到部署一套跑通
Docker 工作流自动化教程|零基础可学
在现代软件开发中,“能在我电脑上跑”已经远远不够。团队协作、持续集成、自动测试、快速部署、环境一致性,都是提高研发效率的关键。Docker 的出现,让应用可以被打包进一个标准化的容器中,从开发、测试到上线,都能保持高度一致。而当我们进一步把 Docker 与脚本、Docker Compose、CI/CD 工具结合起来,就可以实现一套高效的工作流自动化体系。
本文面向零基础读者,会从 Docker 的基本概念讲起,逐步介绍如何构建镜像、运行容器、使用 Docker Compose 管理多服务项目,并最终实现自动化构建、测试与部署的基础流程。
一、为什么要学习 Docker 工作流自动化?
在没有 Docker 的传统开发环境中,经常会遇到这些问题:
- 开发环境和生产环境不一致;
- 新同事配置项目耗时很久;
- 项目依赖版本混乱;
- 本地可以运行,服务器上却报错;
- 部署流程依赖人工操作,容易出错;
- 测试、构建、发布步骤重复繁琐。
Docker 的核心价值在于:把应用程序和运行环境一起打包。也就是说,代码需要什么系统环境、依赖、配置,都可以写在 Dockerfile 或 Docker Compose 文件中。这样,无论是在你的电脑、同事电脑,还是服务器上,只要安装了 Docker,就可以用同样的方式运行项目。
而工作流自动化的目标是进一步减少人工操作。例如:
docker compose up -d
一条命令就可以启动数据库、后端服务、缓存服务等多个组件。
再比如通过 CI/CD 平台,在代码提交后自动完成:
- 拉取代码;
- 安装依赖;
- 构建 Docker 镜像;
- 运行自动化测试;
- 推送镜像到镜像仓库;
- 部署到服务器。
这就是 Docker 工作流自动化的意义:让开发、测试、部署更稳定、更快速、更可重复。
二、Docker 基础概念入门
在正式实践之前,需要先理解几个核心概念。
1. 镜像 Image
镜像可以理解为一个“应用运行环境模板”。它里面包含了操作系统基础文件、运行时、依赖库、应用代码等内容。
例如,一个 Node.js 项目可能需要:
- Linux 系统环境;
- Node.js 运行时;
- npm 或 pnpm;
- 项目源码;
- 项目依赖。
这些都可以被打包成一个 Docker 镜像。
常见镜像包括:
nginx
mysql
redis
node
python
openjdk
ubuntu
alpine
2. 容器 Container
容器是镜像运行起来之后的实例。
如果说镜像是“类”,那么容器就是“对象”;如果说镜像是“安装包”,那么容器就是“正在运行的软件”。
一个镜像可以启动多个容器,例如:
docker run nginx
这条命令会基于 nginx 镜像创建并启动一个容器。
3. Dockerfile
Dockerfile 是用来描述如何构建镜像的文件。它通常写在项目根目录下。
一个简单的 Node.js Dockerfile 示例:
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 3000
CMD ["npm", "run", "start"]
这段配置表示:
- 使用
node:20-alpine作为基础镜像; - 设置工作目录为
/app; - 复制依赖配置文件;
- 安装依赖;
- 复制项目代码;
- 暴露 3000 端口;
- 启动应用。
4. Docker Compose
Docker Compose 用于管理多个容器。实际项目往往不只有一个服务,例如:
- 后端 API 服务;
- MySQL 数据库;
- Redis 缓存;
- Nginx 网关;
- 消息队列。
如果每个服务都用 docker run 手动启动,命令会非常复杂。Docker Compose 可以通过一个 docker-compose.yml 文件统一管理。
三、安装 Docker
1. Windows 和 macOS
Windows 和 macOS 用户可以安装 Docker Desktop。
下载地址:
https://www.docker.com/products/docker-desktop/
安装完成后,在终端输入:
docker version
如果能看到 Docker Client 和 Docker Server 的版本信息,说明安装成功。
再检查 Docker Compose:
docker compose version
注意:新版 Docker Desktop 已经内置 Docker Compose,命令一般是:
docker compose
而不是老版本的:
docker-compose
2. Linux
以 Ubuntu 为例,可以使用官方安装方式,也可以使用系统包管理器安装:
sudo apt update
sudo apt install docker.io docker-compose-plugin -y
启动 Docker:
sudo systemctl start docker
sudo systemctl enable docker
查看版本:
docker version
docker compose version
如果普通用户运行 Docker 报权限问题,可以把当前用户加入 docker 用户组:
sudo usermod -aG docker $USER
然后重新登录终端。
四、从零运行第一个 Docker 容器
我们先运行一个最简单的 Nginx 容器:
docker run -d -p 8080:80 --name my-nginx nginx
参数解释:
docker run:运行容器;-d:后台运行;-p 8080:80:把本机 8080 端口映射到容器 80 端口;--name my-nginx:给容器命名;nginx:使用 nginx 镜像。
然后打开浏览器访问:
http://localhost:8080
如果看到 Nginx 欢迎页,就说明容器运行成功。
查看正在运行的容器:
docker ps
停止容器:
docker stop my-nginx
删除容器:
docker rm my-nginx
删除镜像:
docker rmi nginx
五、为自己的项目编写 Dockerfile
下面以一个简单的 Node.js 项目为例,演示如何容器化一个应用。
假设项目结构如下:
my-app/
├── package.json
├── package-lock.json
├── src/
│ └── index.js
└── Dockerfile
src/index.js 示例:
const http = require("http");
const server = http.createServer((req, res) => {
res.end("Hello Docker Workflow Automation!");
});
server.listen(3000, () => {
console.log("Server is running on port 3000");
});
package.json 示例:
{
"name": "docker-workflow-demo",
"version": "1.0.0",
"scripts": {
"start": "node src/index.js"
},
"dependencies": {}
}
然后编写 Dockerfile:
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 3000
CMD ["npm", "run", "start"]
构建镜像:
docker build -t my-node-app:1.0 .
运行容器:
docker run -d -p 3000:3000 --name my-node-app my-node-app:1.0
访问:
http://localhost:3000
如果页面显示:
Hello Docker Workflow Automation!
说明项目已经成功运行在 Docker 容器中。
六、使用 .dockerignore 优化构建流程
很多初学者会忽略 .dockerignore 文件。它的作用类似 .gitignore,用于告诉 Docker 哪些文件不需要复制进镜像。
例如:
node_modules
npm-debug.log
.git
.gitignore
Dockerfile
docker-compose.yml
README.md
.env
为什么需要 .dockerignore?
- 减少镜像构建上下文;
- 提高构建速度;
- 避免把无关文件打包进镜像;
- 防止敏感信息泄露;
- 降低镜像体积。
尤其是 node_modules,通常不应该直接复制进镜像,而应该在容器环境中重新安装依赖,避免操作系统差异导致依赖不可用。
七、用 Docker Compose 管理多服务项目
现实项目中,后端服务通常需要数据库。下面我们用 Docker Compose 启动一个 Node.js 服务和 MySQL 服务。
项目结构:
my-app/
├── src/
│ └── index.js
├── package.json
├── Dockerfile
├── docker-compose.yml
└── .dockerignore
创建 docker-compose.yml:
services:
app:
build: .
container_name: demo-app
ports:
- "3000:3000"
environment:
DB_HOST: mysql
DB_PORT: 3306
DB_USER: root
DB_PASSWORD: example
DB_NAME: demo
depends_on:
- mysql
mysql:
image: mysql:8.0
container_name: demo-mysql
ports:
- "3306:3306"
environment:
MYSQL_ROOT_PASSWORD: example
MYSQL_DATABASE: demo
volumes:
- mysql-data:/var/lib/mysql
volumes:
mysql-data:
启动服务:
docker compose up -d
查看服务状态:
docker compose ps
查看日志:
docker compose logs -f
停止服务:
docker compose down
如果想连同数据卷一起删除:
docker compose down -v
需要注意的是,depends_on 只能保证 MySQL 容器先启动,并不代表 MySQL 已经完全准备好接收连接。在生产环境中,通常还需要健康检查或重试机制。
八、让开发环境也自动化
Docker 不只适合部署,也适合开发环境标准化。
例如开发时,我们希望修改代码后服务自动重启,可以把本地代码挂载进容器:
services:
app:
build: .
ports:
- "3000:3000"
volumes:
- .:/app
- /app/node_modules
command: npm run dev
如果你的项目使用 nodemon,可以在 package.json 中添加:
{
"scripts": {
"dev": "nodemon src/index.js",
"start": "node src/index.js"
}
}
然后启动:
docker compose up
这样本地修改代码后,容器内的服务可以自动重启,实现更流畅的开发体验。
开发环境自动化的好处包括:
- 新成员无需手动安装数据库;
- 避免本机安装过多依赖;
- 项目环境一键启动;
- 团队环境保持一致;
- 本地测试更接近线上环境。
九、编写常用自动化脚本
虽然 Docker 命令已经比较简洁,但在实际项目中,我们经常会把常用命令封装成脚本。
例如在项目根目录创建 Makefile:
build:
docker compose build
up:
docker compose up -d
down:
docker compose down
logs:
docker compose logs -f
restart:
docker compose down
docker compose up -d
clean:
docker compose down -v
docker system prune -f
使用方式:
make build
make up
make logs
make down
如果团队成员使用 Windows,也可以准备 scripts 目录:
scripts/
├── start.sh
├── stop.sh
├── build.sh
└── logs.sh
start.sh 示例:
#!/bin/bash
docker compose up -d
stop.sh 示例:
#!/bin/bash
docker compose down
赋予执行权限:
chmod +x scripts/*.sh
这样项目启动方式就可以统一为:
./scripts/start.sh
十、构建更规范的镜像版本
初学者经常使用:
docker build -t my-app .
这没有问题,但在团队和生产环境中,建议给镜像添加明确版本号:
docker build -t my-app:1.0.0 .
也可以根据 Git 提交哈希构建:
docker build -t my-app:$(git rev-parse --short HEAD) .
常见镜像标签策略:
| 标签 | 含义 |
|---|---|
latest |
最新版本,不建议生产强依赖 |
1.0.0 |
语义化版本 |
dev |
开发环境版本 |
staging |
预发布环境版本 |
prod |
生产环境版本 |
| Git Hash | 精确对应某次代码提交 |
推荐做法是:生产环境尽量使用明确版本号或 Git Hash,不要只依赖 latest。
十一、镜像推送到仓库
为了让服务器或 CI/CD 平台拉取镜像,需要把镜像推送到镜像仓库。
常见镜像仓库:
- Docker Hub;
- GitHub Container Registry;
- GitLab Container Registry;
- Harbor;
- 阿里云容器镜像服务;
- 腾讯云容器镜像服务。
以 Docker Hub 为例:
登录:
docker login
给镜像打标签:
docker tag my-app:1.0.0 yourname/my-app:1.0.0
推送镜像:
docker push yourname/my-app:1.0.0
服务器拉取镜像:
docker pull yourname/my-app:1.0.0
运行:
docker run -d -p 3000:3000 yourname/my-app:1.0.0
十二、使用 GitHub Actions 实现自动化构建
下面介绍一个基础的 CI/CD 自动化流程:当代码推送到 GitHub 后,自动构建 Docker 镜像并推送到 Docker Hub。
在项目中创建文件:
.github/workflows/docker.yml
内容如下:
name: Docker Build and Push
on:
push:
branches:
- main
jobs:
docker:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Build Docker image
run: |
docker build -t ${{ secrets.DOCKER_USERNAME }}/my-app:${{ github.sha }} .
docker tag ${{ secrets.DOCKER_USERNAME }}/my-app:${{ github.sha }} ${{ secrets.DOCKER_USERNAME }}/my-app:latest
- name: Push Docker image
run: |
docker push ${{ secrets.DOCKER_USERNAME }}/my-app:${{ github.sha }}
docker push ${{ secrets.DOCKER_USERNAME }}/my-app:latest
这里用到了 GitHub Secrets,需要在 GitHub 仓库设置中配置:
DOCKER_USERNAMEDOCKER_PASSWORD
如果你使用 Docker Hub,建议使用 Access Token,而不是直接使用账号密码。
这个工作流完成了:
- 当代码推送到
main分支; - GitHub Actions 自动拉取代码;
- 登录 Docker Hub;
- 构建镜像;
- 打 Git Hash 和 latest 两个标签;
- 推送到镜像仓库。
十三、自动化测试与镜像构建结合
一个更合理的流程应该是:测试通过后才构建和推送镜像。
例如 Node.js 项目可以这样写:
name: Test and Docker Build
on:
push:
branches:
- main
pull_request:
jobs:
test:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Use Node.js
uses: actions/setup-node@v4
with:
node-version: 20
- name: Install dependencies
run: npm ci
- name: Run tests
run: npm test
docker:
runs-on: ubuntu-latest
needs: test
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Build and push
run: |
docker build -t ${{ secrets.DOCKER_USERNAME }}/my-app:${{ github.sha }} .
docker push ${{ secrets.DOCKER_USERNAME }}/my-app:${{ github.sha }}
重点是:
needs: test
这表示 docker 任务依赖 test 任务。只有测试成功后,才会执行 Docker 镜像构建和推送。
十四、服务器端自动部署思路
镜像推送到仓库后,服务器如何自动更新?
最简单的方式是在服务器上执行:
docker pull yourname/my-app:latest
docker compose down
docker compose up -d
可以写成脚本 deploy.sh:
#!/bin/bash
set -e
docker compose pull
docker compose down
docker compose up -d
docker image prune -f
服务器上的 docker-compose.yml 可以写成:
services:
app:
image: yourname/my-app:latest
ports:
- "3000:3000"
environment:
NODE_ENV: production
restart: always
部署时执行:
./deploy.sh
如果想让 GitHub Actions 自动连接服务器部署,可以使用 SSH。大致流程是:
- GitHub Actions 构建并推送镜像;
- 通过 SSH 登录服务器;
- 在服务器执行
docker compose pull; - 重启服务。
不过对于零基础学习者来说,建议先掌握手动部署脚本,再逐步接入自动化部署,避免一开始就把流程做得过于复杂。
十五、Docker 工作流自动化最佳实践
1. Dockerfile 分层要合理
Docker 构建镜像时会使用缓存。把变化不频繁的步骤放前面,可以提高构建速度。
推荐写法:
COPY package*.json ./
RUN npm install
COPY . .
不推荐:
COPY . .
RUN npm install
因为只要代码有任何变动,npm install 就会重新执行。
2. 使用更小的基础镜像
例如:
FROM node:20-alpine
相比完整系统镜像,Alpine 镜像更小,下载更快,部署更轻量。
但也要注意,某些依赖可能需要额外系统库,Alpine 并不总是最佳选择。生产项目应根据依赖情况测试后再决定。
3. 不要把敏感信息写进镜像
不要在 Dockerfile 中写:
ENV PASSWORD=123456
敏感信息应该通过:
- 环境变量;
- Docker secrets;
- CI/CD secrets;
- 云平台密钥管理服务;
进行管理。
4. 区分开发环境和生产环境
开发环境需要热更新、调试工具、源码挂载;生产环境更关注稳定、安全和性能。
可以准备多个 Compose 文件:
docker-compose.yml
docker-compose.dev.yml
docker-compose.prod.yml
启动开发环境:
docker compose -f docker-compose.yml -f docker-compose.dev.yml up
启动生产环境:
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d
5. 定期清理无用资源
Docker 使用久了会产生很多无用镜像、容器、网络和缓存。
查看磁盘占用:
docker system df
清理无用资源:
docker system prune
清理更彻底:
docker system prune -a
注意:清理前要确认不会删除仍需使用的镜像。
十六、常见问题与解决方法
问题 1:端口被占用
报错类似:
Bind for 0.0.0.0:3000 failed: port is already allocated
说明本机 3000 端口已经被占用。
解决方式:
docker ps
查看是否已有容器占用端口,或者修改端口映射:
ports:
- "3001:3000"
问题 2:容器启动后立刻退出
查看日志:
docker logs 容器名
或:
docker compose logs app
常见原因包括:
- 启动命令写错;
- 应用缺少依赖;
- 环境变量未配置;
- 数据库连接失败;
- 端口监听错误。
问题 3:修改代码后容器没变化
可能原因:
- 镜像没有重新构建;
- 容器仍在使用旧镜像;
- 代码没有正确挂载;
- Docker 构建缓存导致结果未更新。
可以尝试:
docker compose build --no-cache
docker compose up -d
问题 4:数据库数据丢失
如果没有使用 volume,容器删除后数据可能会丢失。
正确方式:
volumes:
- mysql-data:/var/lib/mysql
并在底部声明:
volumes:
mysql-data:
十七、推荐学习路线
如果你是零基础,可以按照下面顺序学习:
- 了解镜像和容器的区别;
- 掌握
docker run、docker ps、docker logs、docker stop; - 学会编写 Dockerfile;
- 学会构建和运行自己的镜像;
- 学会使用
.dockerignore; - 学会 Docker Compose;
- 学会用 Compose 管理数据库、缓存和应用;
- 学会编写启动、停止、部署脚本;
- 学会镜像打标签和推送仓库;
- 学习 GitHub Actions 或 GitLab CI;
- 将测试、构建、推送、部署串成自动化流水线。
不要一开始就追求 Kubernetes、服务网格、复杂微服务架构。对于大多数个人项目和中小型团队来说,Docker + Docker Compose + CI/CD 已经能解决大量实际问题。
十八、总结
Docker 工作流自动化的核心不是“记住多少命令”,而是建立一套可重复、可追踪、可自动执行的流程。
一套基础但实用的 Docker 自动化工作流通常包括:
- 使用 Dockerfile 描述应用运行环境;
- 使用
.dockerignore优化构建; - 使用 Docker Compose 管理多容器服务;
- 使用脚本封装常用操作;
- 使用镜像标签管理版本;
- 将镜像推送到远程仓库;
- 使用 CI/CD 自动测试、构建和推送;
- 在服务器上通过 Compose 拉取镜像并重启服务。
当你掌握这些内容后,就可以让项目从“手动配置环境、手动部署”升级为“一键启动、自动构建、自动发布”。这不仅能提升个人效率,也能显著降低团队协作成本。
对于零基础学习者来说,建议从最小项目开始实践:先运行一个 Nginx 容器,再容器化自己的小应用,然后加入数据库,最后接入 GitHub Actions。只要一步步完成,你就能真正理解 Docker 工作流自动化的价值,并把它应用到真实项目中。