06.实战案例

19. 案例一:搭建 Nginx 静态网站

最简单的入门案例:

目录结构:

1
2
3
4
project/
├── docker-compose.yml
└── html/
└── index.html

docker-compose.yml:

1
2
3
4
5
6
7
8
9
10
11
version: "3.8"

services:
nginx:
image: nginx:alpine
container_name: nginx-web
ports:
- "80:80"
volumes:
- ./html:/usr/share/nginx/html:ro
restart: unless-stopped

html/index.html:

1
2
3
4
5
6
7
8
9
<!DOCTYPE html>
<html>
<head>
<title>Hello Docker</title>
</head>
<body>
<h1>Hello from Docker!</h1>
</body>
</html>

运行:

1
2
docker compose up -d
# 访问 http://localhost

20. 案例二:部署 WordPress 博客

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
version: "3.8"

services:
wordpress:
image: wordpress:latest
container_name: wordpress
ports:
- "8080:80"
environment:
WORDPRESS_DB_HOST: mysql
WORDPRESS_DB_USER: wordpress
WORDPRESS_DB_PASSWORD: wordpress_password
WORDPRESS_DB_NAME: wordpress
volumes:
- wordpress-data:/var/www/html
depends_on:
mysql:
condition: service_healthy
networks:
- wp-network
restart: unless-stopped

mysql:
image: mysql:8.0
container_name: wordpress-db
environment:
MYSQL_ROOT_PASSWORD: root_password
MYSQL_DATABASE: wordpress
MYSQL_USER: wordpress
MYSQL_PASSWORD: wordpress_password
volumes:
- mysql-data:/var/lib/mysql
networks:
- wp-network
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
interval: 10s
timeout: 5s
retries: 5
restart: unless-stopped

networks:
wp-network:
driver: bridge

volumes:
wordpress-data:
mysql-data:

运行:

1
2
docker compose up -d
# 访问 http://localhost:8080 完成 WordPress 安装

21. 案例三:Node.js + MySQL + Redis 开发环境

目录结构:

1
2
3
4
5
6
7
project/
├── docker-compose.yml
├── .env
├── Dockerfile
├── package.json
└── src/
└── index.js

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
version: "3.8"

services:
app:
build: .
container_name: node-app
ports:
- "3000:3000"
environment:
NODE_ENV: development
DB_HOST: mysql
DB_PORT: 3306
DB_NAME: ${DB_NAME:-myapp}
DB_USER: ${DB_USER:-root}
DB_PASSWORD: ${DB_PASSWORD:-123456}
REDIS_HOST: redis
REDIS_PORT: 6379
volumes:
- ./src:/app/src # 热重载:源码挂载
- /app/node_modules # 保护 node_modules
depends_on:
mysql:
condition: service_healthy
redis:
condition: service_started
networks:
- dev-network
restart: unless-stopped

mysql:
image: mysql:8.0
container_name: mysql-db
ports:
- "3306:3306" # 开发时方便本地连接
environment:
MYSQL_ROOT_PASSWORD: ${DB_PASSWORD:-123456}
MYSQL_DATABASE: ${DB_NAME:-myapp}
volumes:
- mysql-data:/var/lib/mysql
networks:
- dev-network
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
interval: 10s
timeout: 5s
retries: 5
restart: unless-stopped

redis:
image: redis:7-alpine
container_name: redis-cache
ports:
- "6379:6379" # 开发时方便本地连接
volumes:
- redis-data:/data
networks:
- dev-network
restart: unless-stopped

networks:
dev-network:
driver: bridge

volumes:
mysql-data:
redis-data:

Dockerfile:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
FROM node:18-alpine

WORKDIR /app

# 安装依赖
COPY package*.json ./
RUN npm install

# 复制源码
COPY . .

EXPOSE 3000

# 开发模式使用 nodemon 热重载
CMD ["npm", "run", "dev"]

.env:

1
2
3
DB_NAME=myapp
DB_USER=root
DB_PASSWORD=123456

22. 案例四:企业级日志收集系统(Loki + Grafana)

相比 ELK,Loki + Grafana 更轻量,适合中小规模项目。

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
version: "3.8"

services:
# 日志聚合
loki:
image: grafana/loki:2.9.0
container_name: loki
ports:
- "3100:3100"
volumes:
- ./loki-config.yml:/etc/loki/local-config.yaml
- loki-data:/loki
command: -config.file=/etc/loki/local-config.yaml
networks:
- monitoring
restart: unless-stopped

# 日志收集代理
promtail:
image: grafana/promtail:2.9.0
container_name: promtail
volumes:
- ./promtail-config.yml:/etc/promtail/config.yml
- /var/log:/var/log:ro
- /var/lib/docker/containers:/var/lib/docker/containers:ro
command: -config.file=/etc/promtail/config.yml
networks:
- monitoring
restart: unless-stopped

# 可视化面板
grafana:
image: grafana/grafana:10.0.0
container_name: grafana
ports:
- "3000:3000"
environment:
- GF_SECURITY_ADMIN_USER=admin
- GF_SECURITY_ADMIN_PASSWORD=admin123
volumes:
- grafana-data:/var/lib/grafana
depends_on:
- loki
networks:
- monitoring
restart: unless-stopped

# 示例应用(产生日志)
app:
image: nginx:alpine
container_name: demo-app
ports:
- "80:80"
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"
networks:
- monitoring
restart: unless-stopped

networks:
monitoring:
driver: bridge

volumes:
loki-data:
grafana-data:

loki-config.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
auth_enabled: false

server:
http_listen_port: 3100

ingester:
lifecycler:
ring:
kvstore:
store: inmemory
replication_factor: 1
chunk_idle_period: 5m
chunk_retain_period: 30s

schema_config:
configs:
- from: 2020-10-24
store: boltdb-shipper
object_store: filesystem
schema: v11
index:
prefix: index_
period: 24h

storage_config:
boltdb_shipper:
active_index_directory: /loki/index
cache_location: /loki/cache
shared_store: filesystem
filesystem:
directory: /loki/chunks

limits_config:
enforce_metric_name: false
reject_old_samples: true
reject_old_samples_max_age: 168h

chunk_store_config:
max_look_back_period: 0s

table_manager:
retention_deletes_enabled: false
retention_period: 0s

promtail-config.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
server:
http_listen_port: 9080
grpc_listen_port: 0

positions:
filename: /tmp/positions.yaml

clients:
- url: http://loki:3100/loki/api/v1/push

scrape_configs:
- job_name: containers
static_configs:
- targets:
- localhost
labels:
job: containerlogs
__path__: /var/lib/docker/containers/*/*log
pipeline_stages:
- json:
expressions:
output: log
stream: stream
time: time
- output:
source: output