上一篇 下一篇 分享链接 返回 返回顶部

从零搭建 Docker 自动化工作流:开发、测试到部署一套跑通

发布人:慈云数据-客服中心 发布时间:15小时前 阅读量:0

Docker 工作流自动化教程|零基础可学

在现代软件开发中,“能在我电脑上跑”已经远远不够。团队协作、持续集成、自动测试、快速部署、环境一致性,都是提高研发效率的关键。Docker 的出现,让应用可以被打包进一个标准化的容器中,从开发、测试到上线,都能保持高度一致。而当我们进一步把 Docker 与脚本、Docker Compose、CI/CD 工具结合起来,就可以实现一套高效的工作流自动化体系。

本文面向零基础读者,会从 Docker 的基本概念讲起,逐步介绍如何构建镜像、运行容器、使用 Docker Compose 管理多服务项目,并最终实现自动化构建、测试与部署的基础流程。


一、为什么要学习 Docker 工作流自动化?

在没有 Docker 的传统开发环境中,经常会遇到这些问题:

  • 开发环境和生产环境不一致;
  • 新同事配置项目耗时很久;
  • 项目依赖版本混乱;
  • 本地可以运行,服务器上却报错;
  • 部署流程依赖人工操作,容易出错;
  • 测试、构建、发布步骤重复繁琐。

Docker 的核心价值在于:把应用程序和运行环境一起打包。也就是说,代码需要什么系统环境、依赖、配置,都可以写在 Dockerfile 或 Docker Compose 文件中。这样,无论是在你的电脑、同事电脑,还是服务器上,只要安装了 Docker,就可以用同样的方式运行项目。

而工作流自动化的目标是进一步减少人工操作。例如:

docker compose up -d

一条命令就可以启动数据库、后端服务、缓存服务等多个组件。

再比如通过 CI/CD 平台,在代码提交后自动完成:

  1. 拉取代码;
  2. 安装依赖;
  3. 构建 Docker 镜像;
  4. 运行自动化测试;
  5. 推送镜像到镜像仓库;
  6. 部署到服务器。

这就是 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

  1. 减少镜像构建上下文;
  2. 提高构建速度;
  3. 避免把无关文件打包进镜像;
  4. 防止敏感信息泄露;
  5. 降低镜像体积。

尤其是 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_USERNAME
  • DOCKER_PASSWORD

如果你使用 Docker Hub,建议使用 Access Token,而不是直接使用账号密码。

这个工作流完成了:

  1. 当代码推送到 main 分支;
  2. GitHub Actions 自动拉取代码;
  3. 登录 Docker Hub;
  4. 构建镜像;
  5. 打 Git Hash 和 latest 两个标签;
  6. 推送到镜像仓库。

十三、自动化测试与镜像构建结合

一个更合理的流程应该是:测试通过后才构建和推送镜像

例如 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。大致流程是:

  1. GitHub Actions 构建并推送镜像;
  2. 通过 SSH 登录服务器;
  3. 在服务器执行 docker compose pull
  4. 重启服务。

不过对于零基础学习者来说,建议先掌握手动部署脚本,再逐步接入自动化部署,避免一开始就把流程做得过于复杂。


十五、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:

十七、推荐学习路线

如果你是零基础,可以按照下面顺序学习:

  1. 了解镜像和容器的区别;
  2. 掌握 docker rundocker psdocker logsdocker stop
  3. 学会编写 Dockerfile;
  4. 学会构建和运行自己的镜像;
  5. 学会使用 .dockerignore
  6. 学会 Docker Compose;
  7. 学会用 Compose 管理数据库、缓存和应用;
  8. 学会编写启动、停止、部署脚本;
  9. 学会镜像打标签和推送仓库;
  10. 学习 GitHub Actions 或 GitLab CI;
  11. 将测试、构建、推送、部署串成自动化流水线。

不要一开始就追求 Kubernetes、服务网格、复杂微服务架构。对于大多数个人项目和中小型团队来说,Docker + Docker Compose + CI/CD 已经能解决大量实际问题。


十八、总结

Docker 工作流自动化的核心不是“记住多少命令”,而是建立一套可重复、可追踪、可自动执行的流程。

一套基础但实用的 Docker 自动化工作流通常包括:

  1. 使用 Dockerfile 描述应用运行环境;
  2. 使用 .dockerignore 优化构建;
  3. 使用 Docker Compose 管理多容器服务;
  4. 使用脚本封装常用操作;
  5. 使用镜像标签管理版本;
  6. 将镜像推送到远程仓库;
  7. 使用 CI/CD 自动测试、构建和推送;
  8. 在服务器上通过 Compose 拉取镜像并重启服务。

当你掌握这些内容后,就可以让项目从“手动配置环境、手动部署”升级为“一键启动、自动构建、自动发布”。这不仅能提升个人效率,也能显著降低团队协作成本。

对于零基础学习者来说,建议从最小项目开始实践:先运行一个 Nginx 容器,再容器化自己的小应用,然后加入数据库,最后接入 GitHub Actions。只要一步步完成,你就能真正理解 Docker 工作流自动化的价值,并把它应用到真实项目中。

目录结构
全文