服务公告
Docker-星耀云
发布时间:2026-04-27 16:01
一、前言
搞过的人都知道,服务器多了手动敲docker命令简直是要命——镜像版本不一致、部署流程全靠吼、出了问题连日志都找不到是哪个容器在搞鬼。今天给同行搞一套自动化部署脚本,从镜像构建到容器编排,一条命令搞定所有。
二、操作步骤
-
第一步:检查宿主机环境
先确认机器上docker和docker-compose已经装了,没装的先搞上。
# 检查docker版本 $ docker --version Docker version 24.0.7, build afdd53b # 检查docker-compose版本 $ docker-compose --version Docker Compose version v2.23.0 # 确认docker服务在跑 $ systemctl is-active docker active -
第二步:创建项目目录结构
规范化项目目录,以后再上新服务照着抄就行。
$ mkdir -p /opt/deploy/{app,scripts,configs,logs} $ tree /opt/deploy/ /opt/deploy/ ├── app/ # 应用代码/构建上下文 ├── scripts/ # 部署脚本 ├── configs/ # 配置文件 └── logs/ # 日志挂载目录 -
第三步:准备应用Dockerfile
给应用写Dockerfile,注意多阶段构建减小镜像体积。
$ cat /opt/deploy/app/Dockerfile FROM node:18-alpine AS builder WORKDIR /build COPY package*.json ./ RUN npm ci --only=production FROM node:18-alpine WORKDIR /app COPY --from=builder /build/node_modules ./node_modules COPY . . EXPOSE 3000 CMD ["node", "server.js"] -
第四步:编写docker-compose.yml
定义服务编排,网络、存储、日志全配上。
$ cat /opt/deploy/app/docker-compose.yml version: '3.8' services: app: build: context: ./app dockerfile: Dockerfile container_name: myapp restart: unless-stopped ports: - "3000:3000" environment: - NODE_ENV=production - DB_HOST=db volumes: - ./logs:/app/logs networks: - appnet depends_on: - db logging: driver: "json-file" options: max-size: "10m" max-file: "3" db: image: postgres:15-alpine container_name: myapp-db restart: unless-stopped environment: POSTGRES_DB: myapp POSTGRES_USER: dbuser POSTGRES_PASSWORD: YOUR_PASSWORD volumes: - pgdata:/var/lib/postgresql/data networks: - appnet networks: appnet: driver: bridge volumes: pgdata: -
第五步:写自动化部署脚本
核心脚本,支持回滚、健康检查、灰度发布参数。
$ cat /opt/deploy/scripts/deploy.sh #!/bin/bash set -e APP_NAME="myapp" DEPLOY_DIR="/opt/deploy" VERSION=${1:-latest} HEALTH_PORT=3000 MAX_RETRIES=30 echo "[INFO] 开始部署 $APP_NAME v$VERSION" cd $DEPLOY_DIR echo "[INFO] 拉取最新代码或使用指定版本..." if [ "$VERSION" != "latest" ]; then echo "[INFO] 指定版本: $VERSION" fi echo "[INFO] 构建镜像..." docker-compose -f app/docker-compose.yml build --no-cache echo "[INFO] 停止旧容器..." docker-compose -f app/docker-compose.yml down echo "[INFO] 启动新容器..." docker-compose -f app/docker-compose.yml up -d echo "[INFO] 等待健康检查..." for i in $(seq 1 $MAX_RETRIES); do if curl -sf http://localhost:$HEALTH_PORT/health > /dev/null 2>&1; then echo "[OK] 服务健康检查通过 (尝试 $i/$MAX_RETRIES)" exit 0 fi echo "[WAIT] 健康检查未通过,等待2秒... (尝试 $i/$MAX_RETRIES)" sleep 2 done echo "[ERROR] 健康检查超时,部署失败,执行回滚..." docker-compose -f app/docker-compose.yml down docker-compose -f app/docker-compose.yml up -d exit 1 -
第六步:给脚本加执行权限并测试
脚本写完记得chmod,不然执行报错能让你怀疑人生。
$ chmod +x /opt/deploy/scripts/deploy.sh $ bash /opt/deploy/scripts/deploy.sh latest [INFO] 开始部署 myapp vlatest [INFO] 构建镜像... [INFO] 拉取基础镜像 node:18-alpine node:18-alpine: Pulling from library/node ... Successfully built a1b2c3d4e5f6 Successfully tagged myapp-app:latest [INFO] 停止旧容器... Stopping myapp-db ... done Stopping myapp-app ... done Removing myapp-db ... done Removing myapp-app ... done Removing network deploy_appnet ... done [INFO] 启动新容器... Creating network "deploy_appnet" ... Creating volume "deploy_pgdata" ... Creating container myapp-db ... done Creating container myapp-app ... done [INFO] 等待健康检查... [OK] 服务健康检查通过 (尝试 3/30) -
第七步:配置定时任务实现自动更新(可选)
加个crontab,每天凌晨自动跑一次部署,省得手动操作。
# 编辑crontab $ crontab -e # CentOS/RHEL 和 Ubuntu 通用: # 每天凌晨2点执行部署脚本 0 2 * * * /opt/deploy/scripts/deploy.sh latest >> /var/log/deploy.log 2>&1 # 查看crontab是否生效 $ crontab -l 0 2 * * * /opt/deploy/scripts/deploy.sh latest >> /var/log/deploy.log 2>&1⚠️ 警告:自动更新前务必确认有回滚方案和通知机制,防止凌晨出事故被电话叫醒。
-
第八步:验证部署结果
最后确认容器全在跑,服务正常响应。
$ docker ps CONTAINER ID IMAGE STATUS PORTS NAMES a1b2c3d4e5f6 myapp-app:latest Up 2 minutes 0.0.0.0:3000->3000/tcp myapp b2c3d4e5f6a1 myapp-db:latest Up 2 minutes 5432/tcp myapp-db $ curl -s http://localhost:3000/health {"status":"ok","version":"1.0.0","uptime":120} $ docker logs myapp --tail 20 Server listening on port 3000 Database connected successfully Health check endpoint responding
三、常见问题FAQ
- Q: 镜像构建到一半报错Dockerfile语法没问题怎么回事?
- A: 大概率是构建上下文问题,docker-compose build时context路径要对上。还有种情况是.dockerignore没配好,把node_modules或者.target目录给copy进去了,导致缓存失效重新构建浪费时间。先看报错信息里的Step X,那就是第X行有问题。
- Q: 健康检查一直超时但服务明明能访问怎么办?
- A: 先确认你的应用健康检查端点路径对不对,默认是/health但你可能配的是/ping。还要检查容器网络能不能访问宿主机——有时候docker-compose的网络没创建好会导致跨容器访问失败。用docker exec -it myapp curl localhost:3000/health测试一下。
- Q: 部署脚本报错"permission denied while trying to connect to the Docker daemon",我明明用的root啊?
- A: 那是docker socket权限问题,不是用户权限。检查下docker.sock的属主属组,CentOS/RHEL上可能开了SELinux,Ubuntu上一般是docker组没加对。执行docker ps确认下,能执行就是权限正常的。
- Q: 想做灰度发布怎么搞?
- A: 把deploy.sh改一下,支持传参指定容器标签,用nginx或者traefik做负载均衡,新版本只给10%流量。或者更简单的做法是起两个compose文件,一个myapp-v1一个myapp-v2,通过标签区分,docker-compose scale也能凑合用。
四、总结
核心要点:标准化目录结构、多阶段构建减小镜像体积、docker-compose统一编排、健康检查保底、回滚脚本必备。这套东西跑熟了,每次上新服务就是复制粘贴改个名字的事。
延伸阅读:
- Docker官方文档 - Best practices for writing Dockerfiles
https://docs.docker.com/develop/develop-images/dockerfile_best-practices/ - Traefik动态配置实现灰度发布
https://doc.traefik.io/traefik/user-guides/grpc/ - 《持续交付》- Jenkins CI/CD流水线设计思路值得借鉴
- 监控方案:建议配合prometheus+Grafana监控容器资源,部署脚本加上告警钩子
相关推荐
上一篇: Varnish 自动化-星耀云
下一篇: Python-星耀云