Docker Compose、Dockerfile 编写、私有仓库搭建 — 语法详解与实战案例


一、引入

在实际生产环境中,单容器部署远远不够。我们需要:

  • Dockerfile:自定义镜像,标准化应用环境
  • Docker Compose:编排多容器应用(如 Web + DB + Cache)
  • 私有仓库:安全存储和分发企业内部镜像(如 Harbor)

掌握本章内容,你将能构建完整的企业级容器化部署体系。


二、Dockerfile 编写

1. Dockerfile 基本结构与指令

指令作用示例
FROM基础镜像FROM ubuntu:22.04
LABEL镜像元数据LABEL maintainer="admin@example.com"
RUN执行命令(构建时)RUN apt update && apt install -y curl
COPY复制文件(宿主→镜像)COPY app.py /app/
ADD复制+自动解压(慎用)ADD app.tar.gz /app/
WORKDIR设置工作目录WORKDIR /app
ENV设置环境变量ENV PORT=8080
ARG构建参数(构建时传入)ARG VERSION=1.0
EXPOSE声明端口(非实际映射)EXPOSE 8080
VOLUME声明数据卷VOLUME ["/data"]
USER设置运行用户USER appuser
HEALTHCHECK健康检查HEALTHCHECK --interval=30s CMD curl -f http://localhost:8080/health
CMD容器启动默认命令(可被覆盖)CMD ["python", "app.py"]
ENTRYPOINT入口点(不可被覆盖,常与 CMD 配合)ENTRYPOINT ["python"]

最佳实践:

  • 使用 .dockerignore 忽略不需要的文件
  • 合并 RUN 指令减少层数
  • 使用非 root 用户运行
  • 清理构建缓存(如 apt clean)

📘 案例1:Python Flask 应用 Dockerfile

# 文件:Dockerfile
# 构建一个 Python Flask Web 应用镜像

# 1. 基础镜像
FROM python:3.11-slim

# 2. 标签
LABEL maintainer="dev@example.com" \
      version="1.0" \
      description="Flask Web Application"

# 3. 设置工作目录
WORKDIR /app

# 4. 复制依赖文件(先复制 requirements,利用缓存)
COPY requirements.txt .

# 5. 安装依赖(合并命令,清理缓存)
RUN pip install --no-cache-dir -r requirements.txt && \
    rm -rf /root/.cache

# 6. 创建非 root 用户
RUN useradd --create-home --shell /bin/bash appuser
USER appuser

# 7. 复制应用代码
COPY . .

# 8. 声明端口
EXPOSE 5000

# 9. 健康检查
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
  CMD curl -f http://localhost:5000/health || exit 1

# 10. 启动命令
CMD ["python", "app.py"]

requirements.txt 示例:

Flask==2.3.3
requests==2.31.0

app.py 示例:

from flask import Flask
app = Flask(__name__)

@app.route('/')
def hello():
    return "Hello from Docker!"

@app.route('/health')
def health():
    return "OK", 200

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)

📘 案例2:构建并运行镜像

# 1. 构建镜像(-t 指定标签)
docker build -t my-flask-app:1.0 .

# 2. 查看镜像
docker images | grep my-flask-app

# 3. 运行容器
docker run -d -p 5000:5000 --name flask-app my-flask-app:1.0

# 4. 查看健康状态
docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"

# 5. 访问应用
curl http://localhost:5000
# 输出:Hello from Docker!

# 6. 查看健康检查结果
docker inspect --format='{{json .State.Health}}' flask-app | python -m json.tool

三、Docker Compose 多容器编排

1. Docker Compose 安装(openEuler 24.03)

📘 案例3:安装 Docker Compose

# 1. 下载最新版(替换 vX.X.X 为最新版本)
sudo curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose

# 2. 添加执行权限
sudo chmod +x /usr/local/bin/docker-compose

# 3. 验证安装
docker-compose --version
# 输出:Docker Compose version vX.X.X

2. docker-compose.yml 语法详解

字段作用示例
versionCompose 文件版本version: '3.8'
services定义服务(容器)web:, db:
image使用的镜像image: nginx:latest
build构建上下文build: .build: {context: ., dockerfile: Dockerfile}
ports端口映射ports: ["8080:80"]
volumes数据卷挂载volumes: ["./data:/var/lib/mysql"]
environment环境变量environment: MYSQL_ROOT_PASSWORD: root
depends_on依赖服务depends_on: [db]
networks自定义网络networks: [app-net]
restart重启策略restart: unless-stopped
healthcheck健康检查同 Dockerfile

📘 案例4:LNMP 多容器编排(docker-compose.yml)

# 文件:docker-compose.yml
# 功能:编排 Nginx + PHP + MySQL 服务

version: '3.8'

services:
  # 1. MySQL 服务
  mysql:
    image: mysql:8.0
    container_name: mysql-db
    restart: unless-stopped
    environment:
      MYSQL_ROOT_PASSWORD: MySqlRoot123!
      MYSQL_DATABASE: myapp
    volumes:
      - mysql_data:/var/lib/mysql
    ports:
      - "3306:3306"
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
      interval: 20s
      timeout: 10s
      retries: 3

  # 2. PHP 服务
  php:
    build: ./php  # 使用自定义 Dockerfile
    container_name: php-fpm
    restart: unless-stopped
    volumes:
      - ./www:/var/www/html
    depends_on:
      - mysql

  # 3. Nginx 服务
  nginx:
    image: nginx:latest
    container_name: nginx-web
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./www:/var/www/html
      - ./nginx/conf.d:/etc/nginx/conf.d
    depends_on:
      - php
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost"]
      interval: 30s
      timeout: 10s
      retries: 3

# 定义数据卷
volumes:
  mysql_data:

# 定义网络(默认会创建)
networks:
  default:
    name: lnmp-network

目录结构:

project/
├── docker-compose.yml
├── nginx/
│   └── conf.d/
│       └── default.conf
├── php/
│   ├── Dockerfile
│   └── php.ini
└── www/
    └── index.php

php/Dockerfile:

FROM php:8.2-fpm
RUN docker-php-ext-install mysqli pdo pdo_mysql
COPY php.ini /usr/local/etc/php/
WORKDIR /var/www/html

nginx/conf.d/default.conf:

server {
    listen 80;
    server_name localhost;
    root /var/www/html;
    index index.php index.html;

    location ~ \.php$ {
        fastcgi_pass php:9000;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;
    }
}

www/index.php:

<?php
phpinfo();
?>

📘 案例5:使用 Docker Compose 部署

# 1. 启动所有服务(-d 后台运行)
docker-compose up -d

# 2. 查看服务状态
docker-compose ps

# 3. 查看日志
docker-compose logs nginx

# 4. 实时跟踪日志
docker-compose logs -f php

# 5. 进入容器
docker-compose exec mysql mysql -uroot -p

# 6. 停止服务
docker-compose stop

# 7. 启动已停止的服务
docker-compose start

# 8. 重新构建并启动
docker-compose up -d --build

# 9. 删除所有容器和网络(保留卷)
docker-compose down

# 10. 删除所有(包括卷)
docker-compose down -v

四、私有仓库搭建 — Harbor

Harbor 是企业级 Docker Registry,支持权限管理、漏洞扫描、Web UI。

1. 安装 Harbor(openEuler 24.03)

📘 案例6:安装 Harbor

# 1. 安装必要依赖
sudo dnf install -y yum-utils device-mapper-persistent-data lvm2

# 2. 安装 Docker Compose(如未安装)
sudo curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose

# 3. 下载 Harbor 安装包
wget https://github.com/goharbor/harbor/releases/download/v2.9.0/harbor-offline-installer-v2.9.0.tgz
tar -xzf harbor-offline-installer-v2.9.0.tgz
cd harbor

# 4. 复制配置文件
cp harbor.yml.tmpl harbor.yml

# 5. 编辑配置文件
sudo vim harbor.yml

修改 harbor.yml 关键配置:

hostname: your-server-ip-or-domain  # 如 192.168.1.100
# 注释掉 https 部分(测试环境可不用 HTTPS)
# https:
#   port: 443
#   certificate: /your/certificate/path
#   private_key: /your/private/key/path

# admin 初始密码
harbor_admin_password: Harbor12345

# 数据目录
data_volume: /data/harbor

# 日志目录
log:
  location: /var/log/harbor
# 6. 运行准备脚本
sudo ./prepare

# 7. 启动 Harbor
sudo ./install.sh

# 8. 检查服务状态
sudo docker-compose ps -f

# 9. 访问 Web UI
# 浏览器打开:http://your-server-ip
# 用户名:admin
# 密码:Harbor12345

2. 使用 Harbor 私有仓库

📘 案例7:推送和拉取镜像

# 1. 登录 Harbor(使用 admin 或创建的用户)
docker login your-server-ip -u admin -p Harbor12345

# 2. 标记本地镜像(格式:仓库地址/项目名/镜像名:标签)
docker tag my-flask-app:1.0 your-server-ip/library/my-flask-app:1.0

# 3. 推送镜像到 Harbor
docker push your-server-ip/library/my-flask-app:1.0

# 4. 在 Web UI 查看:http://your-server-ip/harbor/projects

# 5. 从 Harbor 拉取镜像(其他机器)
docker login your-server-ip -u admin -p Harbor12345
docker pull your-server-ip/library/my-flask-app:1.0

# 6. 在 docker-compose.yml 中使用私有镜像
# 修改 docker-compose.yml:
# image: your-server-ip/library/my-flask-app:1.0

✅ 在 Harbor Web UI 中可创建项目、用户、设置权限、扫描漏洞。


五、综合性实战案例


▶ 案例8:微服务架构一键部署(Spring Boot + MySQL + Redis)

# 文件:docker-compose.yml
# 功能:部署 Spring Boot 应用 + MySQL + Redis

version: '3.8'

services:
  # 1. MySQL 服务
  mysql:
    image: mysql:8.0
    container_name: mysql-db
    restart: unless-stopped
    environment:
      MYSQL_ROOT_PASSWORD: root123
      MYSQL_DATABASE: myapp
    volumes:
      - mysql_data:/var/lib/mysql
    ports:
      - "3306:3306"
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
      interval: 20s
      timeout: 10s
      retries: 3

  # 2. Redis 服务
  redis:
    image: redis:7.0
    container_name: redis-cache
    restart: unless-stopped
    ports:
      - "6379:6379"
    volumes:
      - redis_data:/data
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 30s
      timeout: 10s
      retries: 3

  # 3. Spring Boot 应用
  app:
    build: ./app  # 包含 Dockerfile 和 jar 包
    container_name: spring-app
    restart: unless-stopped
    ports:
      - "8080:8080"
    environment:
      SPRING_DATASOURCE_URL: jdbc:mysql://mysql:3306/myapp
      SPRING_DATASOURCE_USERNAME: root
      SPRING_DATASOURCE_PASSWORD: root123
      SPRING_REDIS_HOST: redis
      SPRING_REDIS_PORT: 6379
    depends_on:
      - mysql
      - redis
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8080/actuator/health"]
      interval: 30s
      timeout: 10s
      retries: 3

volumes:
  mysql_data:
  redis_data:

networks:
  default:
    name: microservice-network

app/Dockerfile:

FROM openjdk:17-jdk-slim
WORKDIR /app
COPY *.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]

部署步骤:

# 1. 构建并启动
docker-compose up -d

# 2. 查看日志
docker-compose logs -f app

# 3. 访问应用
curl http://localhost:8080

# 4. 推送到私有仓库(可选)
docker-compose build
docker tag spring-app:latest your-harbor-ip/library/spring-app:1.0
docker push your-harbor-ip/library/spring-app:1.0

▶ 案例9:自动化构建与推送脚本(CI/CD 雏形)

#!/bin/bash
# 文件:build_push.sh
# 功能:自动构建镜像并推送到 Harbor

PROJECT_NAME="my-flask-app"
VERSION="1.0.0"
HARBOR_HOST="192.168.1.100"
HARBOR_PROJECT="library"
HARBOR_USER="admin"
HARBOR_PASS="Harbor12345"

IMAGE_NAME="$HARBOR_HOST/$HARBOR_PROJECT/$PROJECT_NAME:$VERSION"

echo "🚀 开始构建和推送镜像..."

# 1. 构建镜像
docker build -t $IMAGE_NAME .

# 2. 检查构建是否成功
if [ $? -ne 0 ]; then
    echo "❌ 镜像构建失败!"
    exit 1
fi

# 3. 登录 Harbor
echo "$HARBOR_PASS" | docker login $HARBOR_HOST -u $HARBOR_USER --password-stdin

# 4. 推送镜像
docker push $IMAGE_NAME

# 5. 清理本地镜像(可选)
# docker rmi $IMAGE_NAME

# 6. 更新 docker-compose.yml(可选)
sed -i "s|image: .*|image: $IMAGE_NAME|" docker-compose.yml

echo "🎉 镜像构建和推送完成!"
echo "📦 镜像地址: $IMAGE_NAME"

▶ 案例10:Harbor 备份与恢复脚本

#!/bin/bash
# 文件:harbor_backup.sh
# 功能:备份 Harbor 数据和配置

BACKUP_DIR="/backup/harbor/$(date +%Y%m%d_%H%M%S)"
HARBOR_DIR="/path/to/harbor"  # Harbor 安装目录
DATA_DIR="/data/harbor"       # 数据目录

echo "📦 开始备份 Harbor..."

# 1. 创建备份目录
mkdir -p $BACKUP_DIR

# 2. 停止 Harbor 服务
cd $HARBOR_DIR
sudo docker-compose down

# 3. 备份配置文件
cp harbor.yml $BACKUP_DIR/
cp common/config/registry/config.yml $BACKUP_DIR/

# 4. 备份数据目录
tar -czf $BACKUP_DIR/harbor_data.tar.gz -C / data/harbor

# 5. 备份数据库(如果使用外部数据库需单独备份)
# 此处假设使用 Harbor 内置数据库
sudo docker run --rm -v harbor-db:/var/lib/mysql -v $BACKUP_DIR:/backup \
  alpine tar -czf /backup/harbor_db.tar.gz -C /var/lib/mysql .

# 6. 重启 Harbor
sudo docker-compose up -d

# 7. 显示备份结果
ls -lh $BACKUP_DIR

echo "✅ Harbor 备份完成!"
echo "📁 备份位置: $BACKUP_DIR"

六、小结

✅ 本章你已掌握:

  • Dockerfile:编写规范、多阶段构建、健康检查、安全加固
  • Docker Compose:多容器编排、服务依赖、网络配置、健康检查
  • 私有仓库:Harbor 安装、镜像推送/拉取、权限管理
  • 综合实战:微服务部署、自动化构建、Harbor 备份

📌 企业级容器化最佳实践:

  • 使用多阶段构建减小镜像体积
  • 非 root 用户运行容器
  • 使用健康检查确保服务可用性
  • 私有仓库管理企业镜像,避免依赖公网
  • 定期备份 Harbor 数据和配置
  • 结合 CI/CD 工具(如 Jenkins、GitLab CI)实现自动化部署

掌握本章内容后,你将能构建完整的企业级容器化应用部署体系,为云原生转型打下坚实基础!

更多推荐