Docker Compose
Docker Compose 是一个用于定义和运行多容器的 Docker 工具。它允许你使用 YAML 文件配置应用程序的服务、网络和卷,然后使用单个命令启动所有运行所需的容器,包括应用程序的依赖中间件和服务。
注意:
安装 Docker Compose 最方便最推荐的方式是安装 Docker 桌面版。Docker 桌面版包含了 Docker 引擎,Docker CLI 和 Docker Compose。
按需安装 Compose:https://docs.docker.com/compose/install/
添加 compose/docker-compose.json:
services:
lr-event-books-web-node:
build:
context: ../
dockerfile: src/web/Dockerfile
ports:
- 3000:3000
volumes:
- ./config-web.json:/usr/src/app/src/web/config.json
depends_on:
mysql:
condition: service_healthy
kafka:
condition: service_healthy
lr-event-books-trend-node:
build:
context: ../
dockerfile: src/trend/Dockerfile
ports:
- 3001:3001
volumes:
- ./config-trend.json:/usr/src/app/src/trend/config.json
depends_on:
redis:
condition: service_started
kafka:
condition: service_healthy
lr-event-books-rec-node:
build:
context: ../
dockerfile: src/recommendation/Dockerfile
ports:
- 3002:3002
volumes:
- ./config-rec.json:/usr/src/app/src/recommendation/config.json
depends_on:
mongo:
condition: service_started
kafka:
condition: service_healthy
redis:
image: docker.io/bitnami/redis:7.0
environment:
- REDIS_PASSWORD=${REDIS_PASSWORD}
ports:
- 6379:6379
mysql:
image: docker.io/bitnami/mysql:5.7.43
environment:
- MYSQL_DATABASE=lr_book
- MYSQL_USER=test_user
- MYSQL_PASSWORD=${MYSQL_PASSWORD}
- MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}
ports:
- 3306:3306
healthcheck:
test:
[
"CMD",
"mysqladmin",
"ping",
"-h",
"localhost",
"-u",
"root",
"-p$MYSQL_ROOT_PASSWORD",
]
timeout: 20s
retries: 10
volumes:
- ~/lr-mysql-data:/bitnami/mysql/data
mongo:
image: bitnami/mongodb:latest
environment:
- ALLOW_EMPTY_PASSWORD=yes
ports:
- 27017:27017
volumes:
- ~/lr-mongodb-data:/bitnami/mongodb
kafka:
image: bitnami/kafka:latest
environment:
- KAFKA_CFG_AUTO_CREATE_TOPICS_ENABLE=true
- KAFKA_CFG_NODE_ID=0
- KAFKA_CFG_PROCESS_ROLES=controller,broker
- KAFKA_CFG_LISTENERS=PLAINTEXT://:9092,CONTROLLER://:9093
- KAFKA_CFG_ADVERTISED_LISTENERS=PLAINTEXT://kafka:9092
- KAFKA_CFG_LISTENER_SECURITY_PROTOCOL_MAP=CONTROLLER:PLAINTEXT,EXTERNAL:PLAINTEXT,PLAINTEXT:PLAINTEXT
- KAFKA_CFG_CONTROLLER_QUORUM_VOTERS=0@kafka:9093
- KAFKA_CFG_CONTROLLER_LISTENER_NAMES=CONTROLLER
ports:
- 9092:9092
healthcheck:
test:
[
"CMD-SHELL",
"kafka-topics.sh --list --bootstrap-server localhost:9092",
]
interval: 10s
timeout: 10s
retries: 3
在 Docker Compose 中为 MySQL 和 Kafka 找到合适的 healthcheck test(健康检查测试)很不容易。
修复 Topic 问题
为了解决错误“KafkaJSProtocolError: This server does not host this topic-partition
“。
如果没有事先创建好的话,你需要在订阅 topic 之前先创建它。
在终端中执行:
bin/kafka-topics.sh --create --topic lr-book-searches --bootstrap-server localhost:9092
或者,通过代码方式创建:
const kafka = new Kafka(...)
const admin = kafka.admin()
// remember to connect and disconnect when you are done
await admin.connect()
await admin.createTopics({
validateOnly: <boolean>,
waitForLeaders: <boolean>
timeout: <Number>,
topics: <ITopicConfig[]>,
})
await admin.disconnect()
为 Docker Compose 添加配置文件
添加 compose/config-web.json:
{
"app": {
"port": 3000,
"page_size": 5,
"templates_dir": "src/web/adapter/templates"
},
"db": {
"dsn": "mysql://test_user:test_pass@mysql:3306/lr_event_book?charset=utf8mb4"
},
"mq": {
"brokers": ["kafka:9092"],
"topic": "lr-book-searches"
},
"remote": {
"trend_url": "http://lr-event-books-trend-node:3001/trends",
"rec_url": "http://lr-event-books-rec-node:3002/recommendations?uid="
}
}
你需要专供给 Docker Compose 的配置文件版本。因为在该环境里 host,路径,URL 等都变得不一样了。
添加 compose/config-trend.json:
{
"app": {
"port": 3001
},
"cache": {
"host": "redis",
"port": 6379,
"password": "test_pass",
"db": 0,
"timeout": 5000
},
"mq": {
"brokers": ["kafka:9092"],
"topic": "lr-book-searches",
"groupId": "trend-svr"
}
}
添加 compose/config-rec.json:
{
"app": {
"port": 3002,
"pageSize": 10
},
"db": {
"uri": "mongodb://mongo:27017",
"dbName": "lr_event_rec"
},
"mq": {
"brokers": ["kafka:9092"],
"topic": "lr-book-searches",
"groupId": "rec-svr"
}
}
添加 compose/.env:
REDIS_PASSWORD=test_pass
MYSQL_PASSWORD=test_pass
MYSQL_ROOT_PASSWORD=test_root_pass
警醒:
.env
文件应该被.gitignore
设置成忽略。
运行所有服务:
cd compose
docker compose up
你将看到如下内容:
[+] Running 7/7
✔ Container compose-redis-1 Created 0.0s
✔ Container compose-mysql-1 Recreated 0.2s
✔ Container compose-mongo-1 Recreated 0.1s
✔ Container compose-kafka-1 Recreated 0.2s
✔ Container compose-lr-event-books-rec-node-1 Created 0.2s
✔ Container compose-lr-event-books-web-node-1 Created 0.2s
✔ Container compose-lr-event-books-trend-node-1 Created 0.1s
Attaching to kafka-1, lr-event-books-rec-node-1, lr-event-books-trend-node-1, lr-event-books-web-node-1, mongo-1, mysql-1, redis-1
kafka-1 | kafka 07:58:07.37 INFO ==>
kafka-1 | kafka 07:58:07.37 INFO ==> Welcome to the Bitnami kafka container
...
redis-1 | redis 13:24:52.38
redis-1 | redis 13:24:52.39 Welcome to the Bitnami redis container
...
mongo-1 | mongodb 13:24:52.60 INFO ==>
mongo-1 | mongodb 13:24:52.60 INFO ==> Welcome to the Bitnami mongodb container
mongo-1 | mongodb 13:24:52.61 INFO ==> ** Starting MongoDB setup **
...
mysql-1 | mysql 13:24:52.61
mysql-1 | mysql 13:24:52.62 Welcome to the Bitnami mysql container
mysql-1 | mysql 13:24:52.63 INFO ==> ** Starting MySQL setup **
...
你不再需要手动安装那些数据库。它们都被 docker compose 搞定了。
不过,你还是需要在你的 mysql docker 容器里确保lr_event_book
库的存在。CREATE DATABASE lr_event_book CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
放入测试图书,如果没有的话。
curl -X POST -H "Content-Type: application/json" -d '{"title": "To Kill a Mockingbird", "author": "Harper Lee", "published_at": "1960-07-11", "description": "A novel set in the American South during the 1930s, dealing with themes of racial injustice and moral growth."}' http://localhost:3000/api/books
curl -X POST -H "Content-Type: application/json" -d '{"title": "1984", "author": "George Orwell", "published_at": "1949-06-08", "description": "A dystopian novel depicting a totalitarian regime, surveillance, and propaganda."}' http://localhost:3000/api/books
curl -X POST -H "Content-Type: application/json" -d '{"title": "Pride and Prejudice", "author": "Jane Austen", "published_at": "1813-01-28", "description": "A classic novel exploring the themes of love, reputation, and social class in Georgian England."}' http://localhost:3000/api/books
curl -X POST -H "Content-Type: application/json" -d '{"title": "The Catcher in the Rye", "author": "J.D. Salinger", "published_at": "1951-07-16", "description": "A novel narrated by a disaffected teenager, exploring themes of alienation and identity."}' http://localhost:3000/api/books
curl -X POST -H "Content-Type: application/json" -d '{"title": "The Lord of the Rings", "author": "J.R.R. Tolkien", "published_at": "1954-07-29", "description": "A high fantasy epic following the quest to destroy the One Ring and defeat the Dark Lord Sauron."}' http://localhost:3000/api/books
curl -X POST -H "Content-Type: application/json" -d '{"title": "Moby-Dick", "author": "Herman Melville", "published_at": "1851-10-18", "description": "A novel exploring themes of obsession, revenge, and the nature of good and evil."}' http://localhost:3000/api/books
curl -X POST -H "Content-Type: application/json" -d '{"title": "The Hobbit", "author": "J.R.R. Tolkien", "published_at": "1937-09-21", "description": "A fantasy novel set in Middle-earth, following the adventure of Bilbo Baggins and the quest for treasure."}' http://localhost:3000/api/books
curl -X POST -H "Content-Type: application/json" -d '{"title": "The Adventures of Huckleberry Finn", "author": "Mark Twain", "published_at": "1884-12-10", "description": "A novel depicting the journey of a young boy and an escaped slave along the Mississippi River."}' http://localhost:3000/api/books
curl -X POST -H "Content-Type: application/json" -d '{"title": "War and Peace", "author": "Leo Tolstoy", "published_at": "1869-01-01", "description": "A novel depicting the Napoleonic era in Russia, exploring themes of love, war, and historical determinism."}' http://localhost:3000/api/books
curl -X POST -H "Content-Type: application/json" -d '{"title": "Alice’s Adventures in Wonderland", "author": "Lewis Carroll", "published_at": "1865-11-26", "description": "A children’s novel featuring a young girl named Alice who falls into a fantastical world populated by peculiar creatures."}' http://localhost:3000/api/books
curl -X POST -H "Content-Type: application/json" -d '{"title": "The Odyssey", "author": "Homer", "published_at": "8th Century BC", "description": "An ancient Greek epic poem attributed to Homer, detailing the journey of Odysseus after the Trojan War."}' http://localhost:3000/api/books
现在,如果你访问页面 http://localhost:3000/ ,你将看到 3 个微服务提供的所有功能。
用关键词”love“,”peace“和”Odyssey“等进行搜索,然后刷新页面,查看结果。
你的事件驱动微服务体系成功啦! 📢