项目描述:
基于 Linux 环境完成完整 Web 业务容器化落地,全程独立搭建、优化、运维整套容器架构。手动编写 Dockerfile 构建业务镜像并进行分层优化,提升镜像构建效率与安全性;使用 Docker Compose 完成多服务容器编排,统一管理服务启动、依赖、重启逻辑。配置数据卷实现数据持久化,避免容器重建数据丢失;对容器进行 CPU、内存资源配额限制,防止单容器抢占整机资源。部署 cAdvisor 实现容器资源监控,实时查看容器运行状态、资源占用情况。编写 Shell 自动化巡检脚本,结合 Crontab 实现分钟级容器健康巡检,自动识别异常退出容器并自愈重启,完善日志重定向收集,解决容器意外宕机业务中断、人工运维成本高的问题,保障 Web 服务稳定持续运行。
技术栈:
Linux、Shell、Docker、Docker Compose、cAdvisor、容器网络、数据卷持久化、定时任
环境准备:
- 系统:CentOS 7 / CentOS 8 / Ubuntu 均可
- 一台云服务器 / 虚拟机
- 关闭防火墙、关闭 selinux
第一步:安装前的准备:
bash
# 1.更新依赖
[root@docker ~]# yum update -y
# 2.安装依赖工具
[root@docker ~]# yum install -y yum-utils
第二步 安装docker docker compose
bash
[root@docker ~]# cat > /etc/yum.repos.d/docker-ce.repo <<EOF [docker]
name=Docker
baseurl=https://mirrors.aliyun.com/docker-ce/linux/centos/\$releasever/\$basear ch/stable enabled=1 gpgcheck=0 EOF [root@docker ~]# yum clean all
正在更新 Subscription Management 软件仓库。
无法读取客户身份
本系统尚未在权利服务器中注册。可使用 "rhc" 或 "subscription-manager" 进行注册。
17 个文件已删除
[root@docker ~]# yum makecache
正在更新 Subscription Management 软件仓库。
无法读取客户身份
本系统尚未在权利服务器中注册。可使用 "rhc" 或 "subscription-manager" 进行注册。
Docker 117 kB/s | 83 kB 00:00
AppStream 242 MB/s | 7.7 MB 00:00
BaseOS 195 MB/s | 2.1 MB 00:00
元数据缓存已建立。
[root@docker ~]# yum install -y docker-ce docker-ce-cli containerd.io docker-co mpose-plugin
# docker-ce 服务端
# docker-ce-cli 客户端
# containerd.io 容器运行时,底层管理器
# docker-compose-plugin compose的安装包
第三步:开启ip转发配置国内docker加速器:
bash
[root@docker ~]# cat > /etc/sysctl.d/docker.conf <<EOF
net.ipv4.ip_forward = 1
EOF
[root@docker ~]# sysctl --system
* Applying /usr/lib/sysctl.d/10-default-yama-scope.conf ...
* Applying /usr/lib/sysctl.d/50-coredump.conf ...
* Applying /usr/lib/sysctl.d/50-default.conf ...
* Applying /usr/lib/sysctl.d/50-libkcapi-optmem_max.conf ...
* Applying /usr/lib/sysctl.d/50-pid-max.conf ...
* Applying /usr/lib/sysctl.d/50-redhat.conf ...
* Applying /etc/sysctl.d/99-sysctl.conf ...
* Applying /etc/sysctl.d/docker.conf ...
* Applying /etc/sysctl.conf ...
kernel.yama.ptrace_scope = 0
kernel.core_pattern = |/usr/lib/systemd/systemd-coredump %P %u %g %s %t %c %h
kernel.core_pipe_limit = 16
fs.suid_dumpable = 2
kernel.sysrq = 16
kernel.core_uses_pid = 1
net.ipv4.conf.default.rp_filter = 2
net.ipv4.conf.eth0.rp_filter = 2
net.ipv4.conf.lo.rp_filter = 2
net.ipv4.conf.default.accept_source_route = 0
net.ipv4.conf.eth0.accept_source_route = 0
net.ipv4.conf.lo.accept_source_route = 0
net.ipv4.conf.default.promote_secondaries = 1
net.ipv4.conf.eth0.promote_secondaries = 1
net.ipv4.conf.lo.promote_secondaries = 1
net.ipv4.ping_group_range = 0 2147483647
net.core.default_qdisc = fq_codel
fs.protected_hardlinks = 1
fs.protected_symlinks = 1
fs.protected_regular = 1
fs.protected_fifos = 1
net.core.optmem_max = 81920
kernel.pid_max = 4194304
kernel.kptr_restrict = 1
net.ipv4.conf.default.rp_filter = 1
net.ipv4.conf.eth0.rp_filter = 1
net.ipv4.conf.lo.rp_filter = 1
net.ipv4.ip_forward = 1
[root@docker ~]# cat > /etc/docker/daemon.json <<EOF
{
"registry-mirrors": ["https://docker.1ms.run"]
}
EOF
# 这个加速器不太好用 最后花钱有的代理
[root@docker ~]# systemctl daemon-reload
[root@docker ~]# systemctl enable --now docker
Created symlink /etc/systemd/system/multi-user.target.wants/docker.service → /u sr/lib/systemd/system/docker.service.
第四步: 搭建项目目录:
bash
[root@docker ~]# mkdir -p /opt/web/{nginx,mysql,logs,app}
[root@docker ~]# cd /opt/web
[root@docker web]# ll
总用量 0
drwxr-xr-x 2 root root 6 8月 14 12:17 app
drwxr-xr-x 2 root root 6 8月 14 12:17 logs
drwxr-xr-x 2 root root 6 8月 14 12:17 mysql
drwxr-xr-x 2 root root 6 8月 14 12:17 nginx
第五步:创建镜像
bash
[root@docker ~]# vim /opt/web/nginx/Dockerfile
FROM nginx:alpine
# 替换国内源、优化镜像
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories
# 时区统一
RUN apk add --no-cache tzdata && cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
# 拷贝自定义配置
COPY nginx.conf /etc/nginx/conf.d/default.conf
第六步:部署nginx.conf
bash
[root@docker ~]# vim /opt/web/nginx/nginx.conf
server {
listen 80;
server_name localhost;
location / {
root /usr/share/nginx/html;
index index.html;
}
# 日志输出到控制台(方便收集日志)
access_log /dev/stdout;
error_log /dev/stderr;
}
~
第七步:编写 Docker Compose 编排文件
bash
[root@docker ~]# vim /opt/web/docker-compose.yml
version: '3'
services:
nginx:
build: ./nginx
ports:
- "80:80"
volumes:
- ./app:/usr/share/nginx/html # 为了持久化
- ./logs:/var/log/nginx # 为了日志不被丢失
restart: always
depends_on: # 在运行nginx前先运行mysql
- mysql
# 限制资源(企业规范)
deploy:
resources:
limits:
cpus: '0.5'
memory: 256M
mysql:
image: mysql:5.7
ports:
- "3306:3306"
volumes:
- ./mysql:/var/lib/mysql
environment:
MYSQL_ROOT_PASSWORD: 123456
restart: always
第八步:部署测试页面,模拟业务代码
bash
[root@docker ~]# vim /opt/web/app/index.html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>部署测试</title>
</head>
<body>
<h1>Docker Compose 容器化运维项目部署成功</h1>
</body>
</html>
~
运行结果:
bash
[root@docker web]# docker compose up -d
WARN[0000] /opt/web/docker-compose.yml: the attribute `version` is obsolete, it will be ignored, please remove it to avoid potential confusion
[+] up 14/14
✔ Image mysql:5.7 Pulled 1016.9s
[+] Building 7.6s (11/11) FINISHED
=> [internal] load local bake definitions 0.0s
=> => reading from stdin 468B 0.0s
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 270B 0.0s
=> [internal] load metadata for docker.io/library/nginx:alpine 1.2s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> [1/4] FROM docker.io/library/nginx:alpine@sha256:4a73073bd557c65b759505da037898b61f1be6cbcc3c2c3aeac22d2a470c1752 4.0s
=> => resolve docker.io/library/nginx:alpine@sha256:4a73073bd557c65b759505da037898b61f1be6cbcc3c2c3aeac22d2a470c1752 0.0s
=> => sha256:390dc935348d8070e695fbaae2a4bb114fb9e69c59f628e7576036ee9d5244c9 1.40kB / 1.40kB 0.6s
=> => sha256:46519e7231d2eb5604df229beb44d59719a489eaa7aca52982535a010b07a9ed 20.31MB / 20.31MB 2.7s
=> => sha256:d0008c891db48b5f526d914bce9e8d889fe1a9d1f08291ae03fe97f871726f38 1.21kB / 1.21kB 0.7s
=> => sha256:46f977ee452f4399c208714afa034868d6056864f8a0cf3c643ab143dd802c80 404B / 404B 0.5s
=> => sha256:62bec68d7c31c4c8a19d812d84da5f7748e54690c037979945b6c5b6c924b142 957B / 957B 0.2s
=> => sha256:1223f016b4e4a2c21f7c49d4837fbfd47a9da6436b511690ca1e582fc2810d59 627B / 627B 0.2s
=> => sha256:3cd534fe98c64d68a1f4f1c83abb8d5cba7ecfd7be88e592389929d12e6253da 1.89MB / 1.89MB 1.5s
=> => sha256:55afa1ecc21d2bb5e5045f32dafee56272ffd89860bac26f6c32123439af26a4 3.85MB / 3.85MB 2.5s
=> => extracting sha256:55afa1ecc21d2bb5e5045f32dafee56272ffd89860bac26f6c32123439af26a4 0.1s
=> => extracting sha256:3cd534fe98c64d68a1f4f1c83abb8d5cba7ecfd7be88e592389929d12e6253da 0.1s
=> => extracting sha256:1223f016b4e4a2c21f7c49d4837fbfd47a9da6436b511690ca1e582fc2810d59 0.0s
=> => extracting sha256:62bec68d7c31c4c8a19d812d84da5f7748e54690c037979945b6c5b6c924b142 0.0s
=> => extracting sha256:46f977ee452f4399c208714afa034868d6056864f8a0cf3c643ab143dd802c80 0.0s
=> => extracting sha256:d0008c891db48b5f526d914bce9e8d889fe1a9d1f08291ae03fe97f871726f38 0.0s
=> => extracting sha256:390dc935348d8070e695fbaae2a4bb114fb9e69c59f628e7576036ee9d5244c9 0.0s
=> => extracting sha256:46519e7231d2eb5604df229beb44d59719a489eaa7aca52982535a010b07a9ed 0.5s
=> [internal] load build context 0.0s
=> => transferring context: 289B 0.0s
=> [2/4] RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories 0.7s
=> [3/4] RUN apk add --no-cache tzdata && cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime 1.4s
=> [4/4] COPY nginx.conf /etc/nginx/conf.d/default.conf 0.0s
=> exporting to image 0.2s
=> => exporting layers 0.1s
=> => exporting manifest sha256:c50d135099e68af444908be8fc0259d6e3726d26eedd5a2d26709473fac450d9 0.0s
=> => exporting config sha256:7e901ac3ae637979e78d648012b2f6472cb5e1d05ed8fa6d512227630b4f9d02 0.0s
=> => exporting attestation manifest sha256:55cfa8d1e3a8cfd552cb587cb08ef4386b41fa26ff37a35c8f5228486106179d 0.0s
=> => exporting manifest list sha256:a996487fd6f1631e576b0501b769192782a0fc58266cc5d4f08f34ae437236f2 0.0s
=> => naming to docker.io/library/web-nginx:latest 0.0s
[+] up 18/18king to docker.io/library/web-nginx:latest 0.0s
✔ Image mysql:5.7 Pulled 1016.9s
✔ Image web-nginx Built 7.7s
✔ Network web_default Created 0.0s
✔ Container web-mysql-1 Started 0.3s
✔ Container web-nginx-1 Started
页面展示:

做到这里项目基本上框架就做好了
第九步: 部署 cAdvisor 监控容器状态
bash
[root@docker ~]# vim /opt/web/monitor.yml
version: '3'
services:
cadvisor:
image: gcr.nju.edu.cn/cadvisor/cadvisor:v0.49.1
container_name: cadvisor
ports:
- "8080:8080"
volumes:
- /:/rootfs:ro # 这个是读取文件系统占用 磁盘空间 进程等信息
- /var/run:/var/run:ro # # 获取容器基本信息的
- /sys:/sys:ro #容器的cpu 内存 磁盘io
- /var/lib/docker/:/var/lib/docker:ro # docker存储层信息
restart: always
展示页面:

第十步:写一个自动检测容器宕机自动重启的脚本:
bash
[root@docker ~]# vim /opt/web/check.sh
#!/bin/bash
cd /opt/web
if [ $(docker compose ps -a | grep -c Exited) -ne 0 ];then
echo "【异常】检测到容器宕机,执行重启"
docker compose restart
fi
授权加定时任务:
bash
[root@docker web]# chmod +x check.sh
[root@docker web]# crontab -e
*/1 * * * * /opt/web/check.sh >> /opt/web/logs/check.logs 2>&1
展示效果:

看一下又没重启成功:

项目收获与个人总结:
项目收获:
- 完整掌握Docker 全流程落地,熟练手写 Dockerfile、镜像优化、数据卷持久化、容器资源限制、网络配置、启停重启运维逻辑。
- 熟练使用 Docker Compose 完成多容器项目编排,理解容器依赖、启动顺序、集群化单机部署架构。
- 掌握容器监控方案,熟练部署 cAdvisor 监控容器资源使用率、运行状态,具备基础容器运维监控能力。
- 独立开发 Shell 自动化运维脚本,结合 Crontab 实现定时巡检、故障自愈、日志收集,理解生产环境自动化运维思路。
- 深度踩坑并解决 Compose V2 命令兼容、容器状态识别失效、定时任务环境差异、日志丢失等真实生产问题,具备扎实的容器排错、落地、优化能力。
个人总结:
通过本次 Docker 容器化 Web 服务架构搭建项目,我系统掌握了基于容器技术的 Web 服务部署与轻量化运维流程,彻底理解了传统服务器部署与容器化部署的区别,实操能力和架构思维得到了明显提升。
首先,我熟练掌握了 Docker 容器的基础运行原理,理解了内核网络参数对容器服务的重要性。通过配置 docker.conf 内核参数,掌握了开启 IP 转发、网桥流量转发等优化配置的作用,解决了容器网络互通、端口映射、外网访问等常见问题,明白了容器环境需要专门的内核调优才能保证服务稳定运行。
其次,我独立完成了 Nginx Web 服务的容器化配置。亲手编写并优化了 Nginx 站点配置,掌握了监听端口、静态资源目录挂载、日志标准输出等核心配置。尤其理解了容器环境中将日志输出至 /dev/stdout、/dev/stderr 的意义,解决了容器日志无法收集、无法排查问题的痛点,掌握了容器服务标准化日志运维方式。
再者,我熟练掌握了 Docker Compose 自动化编排部署的流程。通过编写 compose 配置文件,实现服务一键创建、启动、重启和销毁,摆脱了手动敲命令部署的繁琐流程,体会到了容器化部署轻量化、可移植、一致性高、运维便捷的优势。同时掌握了日常运维常用命令,能够独立排查容器启动失败、端口冲突、挂载异常、日志异常等常见问题。
最后,本次项目让我建立了完整的容器化 Web 服务架构思维。从内核环境调优、服务配置编写、容器挂载映射,到自动化启动运维,形成了一套完整的部署链路。不仅巩固了 Linux 网络与服务运维基础,也让我对微服务、容器化、自动化运维的工程化思想有了更清晰的认知。