前言
之前部署项目都是手动部署,先装MySQL、Redis、Nginx,然后打包jar包上传到服务器
服务少的时候还行,一多起来就特别麻烦,而且容易出错
所以决定用Docker Compose来统一管理,实现一键部署
其实Docker早就用过,但是都是单个容器跑,这次系统性地用Compose编排服务
Docker Compose简介
Docker Compose是一个用于定义和运行多容器Docker应用程序的工具
通过YAML文件配置服务,然后用一个命令就能启动所有服务
安装的话,Docker Desktop for Windows/Mac自带了,Linux的话单独安装就行
项目结构
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| project/ ├── docker-compose.yml ├── mysql/ │ └── init.sql ├── nginx/ │ ├── nginx.conf │ └── html/ ├── services/ │ ├── user-service/ │ ├── order-service/ │ └── gateway-service/ └── docker/ ├── user-service/Dockerfile ├── order-service/Dockerfile └── gateway-service/Dockerfile
|
编写Dockerfile
先为每个微服务编写Dockerfile
基础镜像
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| FROM openjdk:17-jdk-slim
LABEL maintainer="zhengru"
WORKDIR /app
COPY target/user-service.jar app.jar
EXPOSE 8081
ENTRYPOINT ["java", "-jar", "-Xms512m", "-Xmx512m", "app.jar"]
|
多阶段构建(推荐)
如果觉得镜像太大,可以用多阶段构建:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
|
FROM maven:3.8-openjdk-17 AS builder WORKDIR /app COPY pom.xml . COPY src ./src RUN mvn clean package -DskipTests
FROM openjdk:17-jdk-slim WORKDIR /app COPY --from=builder /app/target/user-service.jar app.jar EXPOSE 8081 ENTRYPOINT ["java", "-jar", "app.jar"]
|
其他服务的Dockerfile类似,就是改一下jar包名和端口
编写docker-compose.yml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124
| version: '3.8'
services: mysql: image: mysql:8.0 container_name: project-mysql environment: MYSQL_ROOT_PASSWORD: root123456 MYSQL_DATABASE: project_db ports: - "3306:3306" volumes: - ./mysql/init.sql:/docker-entrypoint-initdb.d/init.sql - mysql-data:/var/lib/mysql networks: - project-network healthcheck: test: ["CMD", "mysqladmin", "ping", "-h", "localhost"] interval: 10s timeout: 5s retries: 3
redis: image: redis:7-alpine container_name: project-redis ports: - "6379:6379" command: redis-server --appendonly yes volumes: - redis-data:/data networks: - project-network
nginx: image: nginx:alpine container_name: project-nginx ports: - "80:80" - "443:443" volumes: - ./nginx/nginx.conf:/etc/nginx/nginx.conf - ./nginx/html:/usr/share/nginx/html - nginx-logs:/var/log/nginx depends_on: - gateway networks: - project-network
gateway: build: context: . dockerfile: docker/gateway-service/Dockerfile container_name: project-gateway ports: - "8080:8080" environment: SPRING_PROFILES_ACTIVE: prod MYSQL_HOST: mysql MYSQL_PORT: 3306 REDIS_HOST: redis REDIS_PORT: 6379 depends_on: mysql: condition: service_healthy redis: condition: service_started networks: - project-network restart: always
user-service: build: context: . dockerfile: docker/user-service/Dockerfile container_name: project-user-service ports: - "8081:8081" environment: SPRING_PROFILES_ACTIVE: prod MYSQL_HOST: mysql MYSQL_PORT: 3306 REDIS_HOST: redis REDIS_PORT: 6379 depends_on: - mysql - redis networks: - project-network restart: always
order-service: build: context: . dockerfile: docker/order-service/Dockerfile container_name: project-order-service ports: - "8082:8082" environment: SPRING_PROFILES_ACTIVE: prod MYSQL_HOST: mysql MYSQL_PORT: 3306 REDIS_HOST: redis REDIS_PORT: 6379 depends_on: - mysql - redis networks: - project-network restart: always
networks: project-network: driver: bridge
volumes: mysql-data: redis-data: nginx-logs:
|
Nginx配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
| user nginx; worker_processes auto; error_log /var/log/nginx/error.log warn; pid /var/run/nginx.pid;
events { worker_connections 1024; }
http { include /etc/nginx/mime.types; default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on; tcp_nopush on; keepalive_timeout 65;
limit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r/s;
upstream gateway { server gateway:8080; }
server { listen 80; server_name localhost;
location / { root /usr/share/nginx/html; index index.html index.htm; try_files $uri $uri/ /index.html; }
location /api/ { limit_req zone=api_limit burst=20 nodelay;
proxy_pass http://gateway/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme;
proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; } } }
|
MySQL初始化脚本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| CREATE DATABASE IF NOT EXISTS project_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
USE project_db;
CREATE TABLE IF NOT EXISTS user ( id BIGINT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(50) NOT NULL UNIQUE, password VARCHAR(100) NOT NULL, email VARCHAR(100), create_time DATETIME DEFAULT CURRENT_TIMESTAMP );
INSERT INTO user (username, password, email) VALUES ('admin', '$2a$10$N.zmdr9k7uOCQb376NoUnuTJ8iAt6Z5EHsM8lE9lBOsl7iAt6Z5EH', 'admin@example.com');
|
常用命令
构建并启动所有服务
1
| docker-compose up -d --build
|
查看服务状态
查看日志
1 2 3 4 5
| docker-compose logs -f
docker-compose logs -f user-service
|
停止服务
停止并删除容器
停止并删除容器和卷
重启某个服务
1
| docker-compose restart user-service
|
进入容器
1 2 3 4 5 6 7 8
| docker-compose exec mysql bash
docker-compose exec redis sh
docker-compose exec user-service sh
|
环境变量管理
如果不想把配置写在docker-compose.yml里,可以用.env文件:
1 2 3 4 5 6 7 8 9 10
| # .env MYSQL_VERSION=8.0 MYSQL_ROOT_PASSWORD=root123456 MYSQL_DATABASE=project_db
REDIS_VERSION=7-alpine
GATEWAY_PORT=8080 USER_SERVICE_PORT=8081 ORDER_SERVICE_PORT=8082
|
然后在docker-compose.yml里引用:
1 2 3 4 5 6
| services: mysql: image: mysql:${MYSQL_VERSION} environment: MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD} MYSQL_DATABASE: ${MYSQL_DATABASE}
|
生产环境部署
生产环境建议:
- 使用配置中心管理配置
- 敏感信息用secrets管理
- 日志集中收集
- 监控和告警
- 数据定期备份
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| version: '3.8'
services: mysql: environment: MYSQL_ROOT_PASSWORD_FILE: /run/secrets/mysql_root_password secrets: - mysql_root_password volumes: - mysql-backup:/backup
secrets: mysql_root_password: external: true
volumes: mysql-backup:
|
总结
用Docker Compose部署确实方便很多,特别是微服务项目
一个命令就能把所有服务都起来,而且环境隔离,不容易出问题
主要优势:
- 环境一致性
- 快速部署
- 易于扩展
- 配置管理简单
暂时就先记录这么多,后面有其他坑再补充