47 Dockerfile场景化:公司内网业务上线(分角色/分模块)

文章目录

    • 一、总场景:公司内网业务上线(分角色/分模块)
    • 二、任务设计
      • [任务 1:镜像规范化(所有镜像通用)](#任务 1:镜像规范化(所有镜像通用))
      • [任务 2:sshd 镜像"安全化"改造(不要把它当真实生产)](#任务 2:sshd 镜像“安全化”改造(不要把它当真实生产))
      • [任务 3:systemd 镜像的"代价认知 + 正确运行姿势"](#任务 3:systemd 镜像的“代价认知 + 正确运行姿势”)
      • [任务 4:nginx 生产化:反向代理 + 配置挂载 + 日志](#任务 4:nginx 生产化:反向代理 + 配置挂载 + 日志)
      • [任务 5:tomcat 生产化:部署应用 + 环境变量 + 日志](#任务 5:tomcat 生产化:部署应用 + 环境变量 + 日志)
      • [任务 6:MySQL 生产化:持久化 + 初始化脚本 + 权限最小化](#任务 6:MySQL 生产化:持久化 + 初始化脚本 + 权限最小化)
    • [三、综合联调关卡:三层网络 + 只暴露 Nginx](#三、综合联调关卡:三层网络 + 只暴露 Nginx)
    • 四、排障训练(最像生产的部分)
    • 五、交付物要求

下面我把这套 sshd / systemd / nginx / tomcat / mysql 镜像实验,整合成一套更像"生产环境"的实战场景(带任务、验收点、附加项、常见坑),按任务做完基本就能形成完整链路思维: 镜像规范 → 运行参数 → 数据持久化 → 网络隔离 → 安全 → 健康检查 → 日志排障


一、总场景:公司内网业务上线(分角色/分模块)

你们是运维小组,要在一台新服务器上用 Docker 快速部署一个"教学版业务系统":

  • Web 层:Nginx(反向代理 + 静态资源)
  • App 层:Tomcat(跑一个 demo war)
  • DB 层:MySQL(持久化 + 远程访问控制)
  • 运维入口:SSH(仅用于排障演示,不建议真实生产这样用)
  • 系统管理:systemd 容器(演示 systemctl 管理服务的方式与代价)

要求:可重复部署、可迁移、可排障、可回滚


二、任务设计

任务 1:镜像规范化(所有镜像通用)

  1. 每个镜像必须:
    • 有清晰 tag:<service>:<version>-<base>(例 nginx:1.12-centos7
    • Dockerfile 里写注释、分层合理
  2. yum -y update 改成可控(生产里不建议 build 时全量 update)
  3. 清理缓存减小镜像:
    • yum clean all && rm -rf /var/cache/yum

验收点

  • docker images 看 size 是否明显下降
  • Dockerfile 层数是否更少(例如合并 RUN)

附加项

  • 给镜像加 LABEL(维护人、用途、版本、构建时间)

任务 2:sshd 镜像"安全化"改造(不要把它当真实生产)

  1. 禁止 root 密码登录(改用 key)
  2. 只允许某个普通用户(如 ops)登录
  3. SSH 端口改为非 22(容器内仍可 22,宿主映射不同)
  4. 使用更安全的 sshd_config 片段(最少做到:禁用密码、禁用 root、限制用户)

验收点

  • root 不能登录
  • 未授权用户不能登录
  • 只能通过 key 登录

提示

  • PermitRootLogin no
  • PasswordAuthentication no
  • AllowUsers ops

步骤

  • 创建Dokcerfile文件
shell 复制代码
mkidr /opt/myssh
cd /myssh
cp /etc/yum.repos.d/CentOS-Base.repo ./

tee Dockerfile <<-'EOF'
FROM centos:7

LABEL maintainer="this is ssh image <jixuancheng@qq.com>"

ENV ALLOWED_USER=ops

# 添加yum源
RUN rm -rf /etc/yum.repos.d/*
ADD CentOS-Base.repo /etc/yum.repos.d/

# 安装和配置
RUN yum clean all && \
    yum makecache && \
    yum -y install openssh-server openssh-clients sudo && \
    yum clean all && \
    # 创建用户
    useradd -m -s /bin/bash ${ALLOWED_USER} && \
    echo "${ALLOWED_USER}:ops@123" | chpasswd && \
    echo "${ALLOWED_USER} ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers && \
    # 生成主机密钥
    ssh-keygen -t rsa -f /etc/ssh/ssh_host_rsa_key -N '' && \
    ssh-keygen -t ecdsa -f /etc/ssh/ssh_host_ecdsa_key -N '' && \
    # SSH配置
    sed -i \
        -e 's/^#PermitRootLogin.*/PermitRootLogin no/' \
        -e 's/^PasswordAuthentication.*/PasswordAuthentication no/' \
        -e 's/^#PubkeyAuthentication.*/PubkeyAuthentication yes/' \
        /etc/ssh/sshd_config && \
    # 添加用户限制
    echo "AllowUsers ${ALLOWED_USER}" >> /etc/ssh/sshd_config && \
    # PAM配置
    sed -ri '/^session\s+required\s+pam_loginuid.so/ s/^/#/' /etc/pam.d/sshd && \
    sed -i 's/UsePAM yes/UsePAM no/g' /etc/ssh/sshd_config && \
    sed -i 's/#UseDNS yes/UseDNS no/g' /etc/ssh/sshd_config && \
    # 创建.ssh目录
    mkdir -p /home/${ALLOWED_USER}/.ssh && \
    chmod 700 /home/${ALLOWED_USER}/.ssh && \
    chown -R ${ALLOWED_USER}:${ALLOWED_USER} /home/${ALLOWED_USER}/.ssh

EXPOSE 22

CMD ["/usr/sbin/sshd", "-D"]

EOF

UsePAM no:不使用PAM认证
UseDNS no:取消DNS反向认证,加快访问速度。
sed -ri '/^session\s+required\s+pam_loginuid.so/ s/^/#/' /etc/pam.d/sshd:#取消pam限制
ssh-keygen -t rsa -A:生成密钥认证文件
CMD ["/usr/sbin/sshd" , "-D"]:/usr/sbin/sshd -D 用于前台启动sshd服务

  • 客户端连接
shell 复制代码
cd /opt/myssh
# 1. 生成SSH密钥(如果没有的话)
ssh-keygen -t rsa

# 2. 构建镜像
docker build -t myssh-image .

# 3. 创建authorized_keys文件。
cat ~/.ssh/id_rsa.pub > authorized_keys

# 其他客户端需要连服务器上的myssh-server时,将客户端生成的公钥追加到authorized_keys即可。
scp ~/.ssh/id_ed25519.pub root@容器宿主机/opt/sshd/
cat id_ed25519.pub >> authorized_keys


# 4. 运行容器
docker run -d \
  -p 2222:22 \
  -v $(pwd)/authorized_keys:/home/ops/.ssh/authorized_keys \
  --name myssh-server \
  myssh-image

# 5. 连接到容器
ssh -p 2222 ops@容器宿主机
  • myssh-server宿主机
  • 其他客户端登录

报错日志

  • 重复创建容器会提示远程主机标识已更改,删掉~/.ssh/known_hosts该条记录或直接删掉known_hosts文件即可。
ini 复制代码
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@    WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!     @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
shell 复制代码
rm ~/.ssh/known_hosts

任务 3:systemd 镜像的"代价认知 + 正确运行姿势"

你已经写了 systemd 容器清理 wants 的做法,这是很典型的"能跑 systemctl"的实验。

  1. 必须解释清楚:为什么需要 --privileged + cgroup 挂载(安全影响是什么)

systemd 容器需要 --privileged 权限来挂载虚拟文件系统和创建设备节点,并挂载宿主机的 cgroup 来管理服务资源,但此模式赋予了容器等同于宿主机的 root 权限,会引入严重的容器逃逸等安全风险。

  1. 在 systemd 容器里通过 systemctl start/stop/status 管理 sshd 或 mysqld

故障日志

  • --privileged挂载authorized_keys可能导致ops用户访问该文件权限不足root:root。
shel 复制代码
ssh -p 自动获取的端口 ops@localhost

Warning: Permanently added '[localhost]:32770' (ECDSA) to the list of known hosts.
Permission denied (publickey,gssapi-keyex,gssapi-with-mic).

# 解决方法:
docker exec -it myssh-systemd chown ops:ops /home/ops/.ssh/authorized_keys
  1. 写一份"什么时候不该用 systemd 容器"的说明

在追求轻量、快速启动、高安全性的生产环境及微服务部署场景中,不应该使用 systemd 容器;它应仅限于开发测试或传统应用迁移的过渡场景。

场景 推荐方案 理由
开发/测试环境 systemd 容器 模拟完整系统环境
生产微服务 直接前台启动 符合云原生理念
传统应用迁移 systemd 容器(过渡期) 减少迁移成本
边缘计算 直接前台启动 资源利用效率高
学习 systemd systemd 容器 提供真实操作环境

验收点

  • systemctl 能正常查看服务状态
  • 能重启服务后仍正常

附加项

  • 对比:不用 systemd 的做法(容器前台启动 vs systemctl)优缺点
    systemd
    优点:熟悉、服务管理方便
    缺点:启动慢、要特权、镜像大
    直接启动
    优点:启动快、安全、镜像小
    缺点:要手动管理

任务 4:nginx 生产化:反向代理 + 配置挂载 + 日志

  1. Nginx 镜像不再把配置写死在镜像里:用 volume 挂载
    • /usr/local/nginx/conf/nginx.conf
    • /usr/local/nginx/conf/conf.d/
  2. Nginx 反向代理到 Tomcat(例如 /app → tomcat:8080)
  3. 日志持久化挂载:
    • /usr/local/nginx/logs/

步骤

shell 复制代码
# 1. 准备软件源和nginx源码包
cd /opt/nginx-centos7
ls
CentOS-Base.repo  nginx-1.20.2.tar.gz

# 2. 编写Dockerfile
tee Dockerfile <<-'EOF'
# 基于基础镜像
FROM centos:7
# 用户信息
MAINTAINER this is nginx image <jixuancheng@qq.com>
# 添加yum源
RUN rm -rf /etc/yum.repos.d/*
ADD CentOS-Base.repo /etc/yum.repos.d/
# 安装依赖环境
RUN yum -y install pcre-devel zlib-devel gcc gcc-c++ make curl && \
    yum clean all && \
    useradd -M -s /sbin/nologin nginx
# 上传nginx软件压缩包,并解压
ADD nginx-1.20.2.tar.gz /opt/
# 指定工作目录
WORKDIR /opt/nginx-1.20.2
RUN ./configure \
    --prefix=/usr/local/nginx \
    --user=nginx \
    --group=nginx \
    --with-http_stub_status_module && \
    make -j $(nproc) && make install
ENV PATH /usr/local/nginx/sbin:$PATH
# 创建必要的目录结构(容器第一次运行时)
RUN mkdir -p /usr/local/nginx/conf/conf.d && \
    mkdir -p /usr/local/nginx/logs
# 声明数据卷(最佳实践:声明但不自动挂载)
VOLUME ["/usr/local/nginx/conf", "/usr/local/nginx/logs", "/usr/local/nginx/html"]
# 指定http和https端口
EXPOSE 80
EXPOSE 443
# 健康检查
HEALTHCHECK --interval=30s \
  --timeout=3s \
  --start-period=5s \
  --retries=3 \
  CMD curl -f http://localhost/nginx_status || exit 1
# 关闭 nginx 在后台运行
CMD ["/usr/local/nginx/sbin/nginx", "-g", "daemon off;"]
EOF

# 3. 准备挂载目录
mkdir -p /data/nginx/{conf,logs,html}

# 4. 构建镜像并启动容器
docker build -t nginx:centos7 .
docker network create --subnet=172.18.0.0/16 webnet
docker run -d --name nginx-centos7 \
  --net webnet --ip 172.18.0.10 \
  -p 80:80 -p 443:443 \
  -v /data/nginx/conf:/usr/local/nginx/conf \
  -v /data/nginx/logs:/usr/local/nginx/logs \
  -v /data/nginx/html:/usr/local/nginx/html \
  nginx:centos7

# 5. 拷贝初始配置文件、日志、和页面。
docker cp nginx-test:/usr/local/nginx/conf/. /data/nginx/conf/
docker cp nginx-test:/usr/local/nginx/logs/. /data/nginx/logs/
docker cp nginx-test:/usr/local/nginx/html/. /data/nginx/html/
# 在宿主机给挂载的目录赋权
chmod -R 755 /data/nginx/
# 在容器修改挂载目录的归属(可选)
chown -R nginx:nginx /usr/local/nginx 

# 6. 重新加载nginx配置文件
docker exec -it nginx-centos7 nginx -s reload

验收点

  • 修改宿主机配置后,reload 生效(容器不重建)
  • curl http://宿主IP:端口/app 能访问到 tomcat
  • 日志在宿主机可见

附加项

  • 做健康检查:用 curl 检测 200
shell 复制代码
curl -I http://localhost
HTTP/1.1 200 OK

任务 5:tomcat 生产化:部署应用 + 环境变量 + 日志

  1. Tomcat 镜像做到"应用可插拔":
    • 通过 volume 挂载 webapps/ 或挂载 war 包
  2. 配置 JVM 参数通过环境变量传入(如 JAVA_OPTS
  3. 日志持久化(logs/

验收点

  • 替换 war 包无需重建镜像
  • 设置 JAVA_OPTSps 可看到
  • 日志落盘到宿主机

任务 6:MySQL 生产化:持久化 + 初始化脚本 + 权限最小化

  1. 数据必须持久化(volume)
  2. 初始化动作要可重复(首次初始化执行,已有数据不重复初始化)
  3. 权限控制:不要 grant all on *.* to root@'%' 作为最终答案
    • 改为创建业务库、业务用户,只授权业务库

验收点

  • 删除容器重建,数据不丢
  • 业务用户只能访问指定库
  • 远程能连,但 root 不允许随便远程(作为加分)

问题

  • 为什么生产里更推荐官方 mysql 镜像(减少编译维护成本)

三、综合联调关卡:三层网络 + 只暴露 Nginx

目标拓扑

  • frontend_net:只放 nginx,对外暴露端口
  • backend_net:tomcat + mysql 在内网,外部不可直接访问
  • nginx 同时加入两个网络做桥接(或只做反代到 backend)

任务

  1. 创建两个网络
  2. mysql 不映射宿主机端口(禁止外部直连)
  3. 只能通过 nginx 访问到业务页面
  4. tomcat 只能被 nginx 访问(外部不映射)

验收点

  • docker ps 只有 nginx 有 0.0.0.0:xxxx->80
  • 从宿主机直接连 mysql 失败
  • 从 nginx 容器能连 mysql(或 tomcat 能连 mysql)

四、排障训练(最像生产的部分)

要求在限定时间内定位问题并修复:

  1. nginx 502
    • tomcat 未启动 / upstream 写错 / 网络不通
      验收:能解释原因 + 修复
  2. tomcat 启动但访问 404
    • war 未部署 / context 路径错
      验收:能找到 webapps 内容并修复映射
  3. mysql 能启动但远程连不上
    • 授权、bind-address、端口没暴露、网络不通
      验收:能说明"该不该暴露端口",并给出更安全的连接方式
  4. 数据丢失
    • 忘了 volume
      验收:能复现、能给出修复方案、能解释原理

五、交付物要求

最后提交:

  1. 每个服务的 Dockerfile(或 compose 文件)
  2. 一份部署文档(含端口、网络、账号策略)
  3. 一份回滚方案(如何回到上一版镜像)
  4. 一份安全说明(哪些设置仅用于实验、生产要怎么改)
相关推荐
machunlin~2 小时前
centos 系统安装相关
linux·运维·docker·centos
小代码20162 小时前
ubuntu vscode docker php 环境搭建
vscode·ubuntu·docker·php·laravel
无泪无花月隐星沉2 小时前
续写云计算的前世今生
kubernetes·云计算·openstack
程序终结者3 小时前
CDH6.3.2集群docker容器化离线部署客户端parcel+配置全流程详解
运维·docker·容器
ERP面壁者3 小时前
Docker小白搭建xxl-job,mysql的过程日志
mysql·docker·容器
iconball3 小时前
个人用云计算学习笔记 --30 华为云存储云服务
运维·笔记·学习·华为云·云计算
青花锁3 小时前
Mac电脑安装Docker
macos·docker·容器
Fortune_yangyang3 小时前
docker 搭建lnmp
运维·docker·容器
howard20053 小时前
Docker实战:使用CGroups控制资源
docker·cgroups