有句话说在前面CentOS 7虽然已经进入了生命周期后期但真实生产环境里跑着的存量机器依然非常多很多公司到现在还在用CentOS 7.9做服务器系统。如果你也是刚拿到一台CentOS 7的云服务器或者公司给你分配了一台旧机器让你装Docker那这篇教程就是给你准备的。我尽量把每一步都拆开讲清楚不光是“敲什么命令”还会告诉你“为什么这么敲”、“不这么敲会踩什么坑”。整个部署过程我实测过很多遍按着下面的顺序走基本不会出问题。1. 部署前准备与环境检查1.1 先确认系统版本和内核很多人拿到服务器就直接开始装Docker装完报错才发现内核版本太低或者系统本身是CentOS 6.x这属于白忙活。所以第一步永远是检查环境。cat /etc/centos-release正常你应该看到类似这样的输出CentOS Linux release 7.9.2009 (Core)如果输出的是CentOS 6.x那下面的教程对你就没意义了因为CentOS 6的Docker版本停留在很久以前而且很多依赖包都拉不下来建议直接重装系统。接着看内核版本uname -rDocker要求CentOS 7的内核版本必须在3.10以上大多数CentOS 7.9默认内核都在3.10.0-1160左右这是能满足要求的。如果你看到的是3.10.0-327之类的也能用但建议后续有精力时升级一下内核后面我会在常见问题里专门说这事。1.2 检查关键模块是否加载Docker依赖一些内核模块和iptables相关功能尤其是overlay2存储驱动和bridge网络这两个是Docker能正常工作的基础。lsmod | grep overlay lsmod | grep br_netfilter如果上面两条命令没有输出说明模块没加载需要手动启用modprobe overlay modprobe br_netfilter然后确认net.bridge.bridge-nf-call-iptables参数是开启的这个参数决定了容器网络能不能正常转发sysctl -a | grep bridge-nf-call-iptables如果是0或者没输出就把它写进系统配置cat EOF | sudo tee /etc/sysctl.d/docker.conf net.bridge.bridge-nf-call-iptables 1 net.bridge.bridge-nf-call-ip6tables 1 net.ipv4.ip_forward 1 EOF sysctl -p /etc/sysctl.d/docker.conf这一步在云服务器上尤其重要我遇到过好几台机器没开ip_forward导致容器能启动但访问不了外网排查了很久才找到是这个参数的问题。1.3 yum源和网络连通性检查安装Docker需要联网而且yum源要能正常使用。先测一下yum能不能解析yum -y update如果你的服务器带宽不大这个步骤可能要几分钟属于正常现象。但如果你执行yum update的时候报错比如“Could not retrieve mirrorlist”之类的那就说明yum源有问题建议先把源换成国内镜像源。这里说一个经验如果你是在国内服务器上操作yum源最好直接用阿里云镜像站或者清华源因为默认的CentOS官方源在国内访问速度很慢碰到网络波动还会超时。另外还要检查一下系统时间dateDocker和很多HTTPS仓库都依赖证书验证如果系统时间和实际时间差太多装完Docker之后拉镜像也会报证书错误这个问题我从没见系统教程里提过但实际踩坑概率很高。注意时间不准、yum源不通、内核模块没加载这三个问题任何一个都会在中途打断你而且报错信息特别容易误导人。与其装到一半再排查不如一开始就花五分钟全查一遍。2. 完整安装Docker CE2.1 清理旧版本与安装依赖包如果你以前装过老版本的Docker比如通过yum装过docker或者docker-io建议先卸载干净否则会和docker-ce起冲突。yum remove docker \ docker-client \ docker-client-latest \ docker-common \ docker-latest \ docker-latest-logrotate \ docker-logrotate \ docker-engine如果你确认机器上从来没装过Docker这一步可以跳过。然后安装依赖工具包yum install -y yum-utils device-mapper-persistent-data lvm2这三个包的作用分别是yum-utils提供yum-config-manager命令用来添加和修改yum仓库device-mapper-persistent-data和lvm2是Docker的devicemapper存储驱动依赖。虽然现在Docker默认用overlay2但装这两个包属于官方文档里的标准流程能保证兼容性。2.2 配置Docker的yum仓库这一步有两种做法一种是指向Docker官方源一种是指向国内镜像源。我直接把两个方案都给你自己按网络情况选一个。官方源适合海外服务器或者网络好的情况yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo阿里云镜像源适合国内服务器速度明显快很多yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo走阿里云源的话添加完仓库之后要顺手把repo文件里的URL替换成阿里云地址避免它跳回官方源sed -i s/download.docker.com/mirrors.aliyun.com\/docker-ce/g /etc/yum.repos.d/docker-ce.repo这里多说一句不要觉得“反正都是源随便配一个算了”。我实测过国内机器用官方源拉docker-ce的时候经常卡在metadata下载阶段等很久才出结果换成阿里云源之后整个安装过程一分钟内就能结束。这种体验差距会直接影响你后面所有操作的效率。2.3 安装docker-ce及核心组件仓库配置好之后执行yum install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin这里的几个包拆开说一下docker-ceDocker引擎本体守护进程所在。docker-ce-cli命令行工具也就是你平时敲的docker命令。containerd.io容器运行时Docker引擎用它来实际管理容器的生命周期。docker-buildx-plugin和docker-compose-plugin官方插件分别用来增强镜像构建和Docker Compose编排。如果你用的yum源版本比较老可能找不到buildx和compose插件这时候只装前三个也能正常工作缺的Compose可以按后面第4章的方式单独装。安装完成后先别急着启动先把开机自启配好systemctl enable docker systemctl start docker然后看一眼运行状态systemctl status docker如果你看到类似这样的输出说明Docker已经在运行了● docker.service - Docker Application Container Engine Loaded: loaded (/etc/systemd/system/docker.service; enabled; vendor preset: disabled) Active: active (running) since ...注意有不少教程会让你执行service docker start在CentOS 7上这么做不是不行但systemd的systemctl才是正统方式。用systemctl的好处是能同时管理开机自启和守护进程状态排查问题也更方便。2.4 验证安装结果输入版本命令确认一下docker version正常情况下你看到的Client和Server版本应该是一致的比如都显示20.10.x或24.0.x。如果Client有输出但Server报错说明Docker守护进程没起来需要检查系统日志journalctl -u docker -n 50最后用经典的hello-world镜像跑一遍完整验证docker run hello-world这一步会从镜像仓库拉取一个测试镜像并运行容器容器的任务就是打印一句“Hello from Docker!”看到这句话说明你的整个Docker链路是通的。有一个细节说一下如果hello-world拉取特别慢或者直接超时不是你服务器的问题就是网络访问Docker Hub不通畅。这时候别硬等直接跳到第3章配一个镜像加速器配完再跑hello-world就能秒过。3. Docker核心配置与镜像加速3.1 daemon.json配置文件详解Docker的守护进程配置都在/etc/docker/daemon.json里这个文件默认是不存在的需要自己创建。它影响着镜像拉取速度、容器日志大小、数据存储位置等关键行为。我建议你在装好Docker之后第一件事就创建这个文件把下面这些配置写进去{ registry-mirrors: [https://你的加速器地址], log-driver: json-file, log-opts: { max-size: 100m, max-file: 3 }, data-root: /var/lib/docker, ipv6: false }简单解释一下每个配置项的目的registry-mirrors镜像加速器地址国内服务器必须要配否则拉镜像慢到怀疑人生。log-driver和log-opts限制容器日志大小。这是很多人忽略的大坑Docker默认不限制日志文件大小一个容器长期不清理日志能占用几十G甚至上百G磁盘我见过最离谱的一次是nginx日志把200G的磁盘直接写满了。>systemctl daemon-reload systemctl restart docker然后执行docker info查看输出里的Registry Mirrors一栏确认加速器已经生效。3.2 修改Docker数据目录的完整步骤如果你的系统盘只有40G而数据盘有100G以上那强烈建议把Docker的数据目录挪到数据盘上。具体操作如下# 停止Docker服务 systemctl stop docker # 创建目标目录并同步已有数据如果没有数据就直接跳过同步 mkdir -p /data/docker cp -r /var/lib/docker/* /data/docker/ # 在daemon.json里修改data-root # 把data-root: /var/lib/docker改成data-root: /data/docker # 重启Docker systemctl daemon-reload systemctl start docker如果你已经跑了不少容器特别是容器里还有数据库这类有状态应用改data-root之前一定要确认同步完整最好用rsync而不是cp因为容器运行时会持续写入文件cp的数据可能会不一致。最稳妥的办法是先停Docker再做同步同步完先别删旧目录等新目录运行几天确认无误后再清理。3.3 常用命令速查Docker的命令体系比较庞大但对于刚部署完环境的阶段你主要会用到下面这些场景命令查看运行中的容器docker ps查看所有容器docker ps -a查看本地镜像docker images拉取镜像docker pull 镜像名:标签启动容器docker run -d --name 容器名 镜像名进入容器交互docker exec -it 容器名 bash查看容器日志docker logs -f 容器名停止/启动/重启容器docker stop/start/restart 容器名删除容器docker rm -f 容器名删除镜像docker rmi 镜像名查看资源占用docker stats这些命令先用熟再往深处慢慢研究docker network和docker volume不用一上来就背所有参数实际用多了自然就记住了。提示docker run -d --name 这个组合是我日常用得最频繁的组合。挂载目录、映射端口、设置环境变量这些参数如果记不住用docker run --help查就行别去死记参数含义。4. Docker Compose的部署与使用4.1 安装Docker ComposeDocker Compose是用来管理多个容器的编排工具用一条命令同时启动、停止、重建一组相关联的容器。对于刚部署完Docker的人要想跑nginx、mysql、redis这类常见组合Compose几乎是必备的。如果你在前面的安装步骤里用yum装上了docker-compose-plugin那可以直接验证一下docker compose version如果提示没有这个命令就用独立安装方式curl -L https://github.com/docker/compose/releases/download/v2.24.0/docker-compose-$(uname -s)-$(uname -m) -o /usr/local/bin/docker-compose chmod x /usr/local/bin/docker-compose ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose国内服务器拉GitHub上的资源慢是常态如果这个curl命令卡住可以试着从国内镜像站下载Compose或者用python的pip方式装。不管用哪种方式装完之后确认版本docker-compose --version看到版本号输出就说明装好了。4.2 用Compose编排一个NginxMySQL实例为了让你直观感受Compose的用法我写一个最小可用的docker-compose.yml示例。假设我们要在服务器上跑一个Nginx和一个MySQL 8.0version: 3.8 services: nginx: image: nginx:1.24-alpine container_name: web-nginx ports: - 80:80 - 443:443 volumes: - ./nginx/html:/usr/share/nginx/html - ./nginx/conf:/etc/nginx/conf.d - ./nginx/logs:/var/log/nginx restart: always mysql: image: mysql:8.0 container_name: web-mysql ports: - 3306:3306 environment: MYSQL_ROOT_PASSWORD: YourStrongPassword MYSQL_DATABASE: webapp MYSQL_USER: webuser MYSQL_PASSWORD: WebUserPassword volumes: - ./mysql/data:/var/lib/mysql restart: always然后在这个文件所在目录执行docker-compose up -dCompose会按照配置自动拉取镜像、创建容器、建立网络。观察一下执行过程你会发现它默认会创建一个以目录名命名的网络nginx和mysql两个容器都在这个网络内它们之间可以通过服务名直接互相访问。比如nginx容器内部可以用mysql这个主机名去访问数据库这就是Compose最核心的价值容器之间不需要再手写IP地址互连。4.3 数据持久化必须写在前面上面示例里的volumes配置是必须的千万不能省。如果容器删了重建而数据没有挂载到宿主机那所有数据都会跟着容器一起消失。以MySQL为例官方镜像的默认数据目录在/var/lib/mysql如果你不挂载宿主机目录容器一删数据库就没了。挂载了./mysql/data之后数据实际存储在宿主机上容器随便删随便重建数据都还在。这里有一个我踩过的坑MySQL 8.0的官方镜像默认会初始化数据库目录挂载空目录启动时会自动写入数据但如果挂载的目录已经存在非空文件尤其是权限不对的情况MySQL会初始化失败。解决办法是先把宿主机的目录权限设置好比如chmod -R 778 ./mysql/data或者先让容器用默认配置启动一次再停掉容器把数据拷贝出来。nginx的日志目录同理不挂载的话日志只在容器内部容器一删日志全没。生产环境里日志是排障的第一手资料丢失成本很高建议从一开始就养成“所有有状态的数据必须挂载”的习惯。4.4 Compose常用操作命令docker-compose up -d创建并后台启动所有服务docker-compose ps查看当前项目容器状态docker-compose logs -f跟踪所有服务的日志输出docker-compose restart重启所有服务docker-compose down停止并移除所有容器和网络docker-compose down -v额外删除所有数据卷注意这会导致数据丢失关于Compose给一个明确建议不同项目的服务尽量分开目录部署每个目录有自己的docker-compose.yml。比如/opt/nginx-web和/opt/mysql-cluster各自独立不要把所有服务塞在一个Compose文件里一方面影响独立升级另一方面某个服务的配置错误会影响整个项目。5. 常见问题与排查技巧实录5.1 典型问题速查表问题现象根本原因解决方法docker run报Cannot connect to the Docker daemonDocker服务未启动或启动失败systemctl status docker查看日志拉取镜像超时或报EOF网络访问Docker Hub不通配置镜像加速器容器能创建但访问不了外网net.ipv4.ip_forward未开启sysctl -w net.ipv4.ip_forward1并持久化容器日志占满磁盘未配置日志切割策略配置daemon.json的log-opts并重建容器启动MySQL容器报Cant open file权限错误宿主机挂载目录权限不对chmod 755或778对应数据目录端口被占用导致容器启动失败宿主机已有进程占用端口检查端口占用并调整映射docker-compose命令找不到未安装Compose插件或独立安装失败重新安装并添加执行权限Docker重启后容器没有自动恢复容器创建时未配置restart策略docker update --restartalways 容器名5.2 内核模块和版本相关的翻车现场这是比较常见的问题尤其是老机器或者最小化安装的CentOS 7。如果你启动容器的时候报类似这样的错Error response from daemon: failed to create task for container: failed to create shim task: OCI runtime create failed: ... : open /dev/... no such file or directory或者kernel: overlayfs: unsupported and detected problem多半是overlay模块未加载或者内核版本太老。前面第1.2节已经让你提前加载过模块了但如果你内核本身就是3.10.0-327这种老版本overlay2可能不稳定。这种情况下有两个选择升级内核到3.10.0-1160以上或直接换到4.x/5.x主线内核。在daemon.json里设置storage-driver: vfs强制换存储驱动。但vfs性能和空间利用率都远不如overlay2只适合临时过渡不推荐生产使用。还有一个藏在底下的坑如果你用的是云服务商提供的CentOS 7自定义镜像有些镜像会阉割一些内核模块。遇到这种情况先试modprobe overlay如果提示Module not found那基本可以确认内核模块缺失只能考虑换内核或者换系统。5.3 iptables与防火墙的相爱相杀Docker在创建容器时会默认写入iptables规则而且它会直接管理nat表里的规则。如果你在宿主机上手动配置了firewalld或者iptables规则可能会和Docker的规则互相覆盖表现为宿主机端口明明开着但外面就是访问不到容器映射的端口。排查思路先确认容器在跑docker ps确认端口映射docker port 容器名检查宿主机防火墙firewall-cmd --list-all检查iptables nat表iptables -t nat -L -nCentOS 7上很多安全基线加固的脚本会顺手清掉Docker自己的链路导致重启后端口映射失效所以如果系统加固过重装Docker之后一定要检查iptables的DOCKER链是否存在。我处理过的一台机器就是这样内网其他机器访问不了Docker端口排查到最后一查iptables发现DOCKER链整个不见了重建Docker网络才恢复。5.4 日志清理的正确姿势如果你已经跑了几周容器但之前没配日志切割可能会出现磁盘突然告警的情况。这时候可以先查看哪个容器占的日志最多du -sh /var/lib/docker/containers/*/找到大文件之后不要直接rm那个json.log文件因为这可能导致Docker读写句柄异常。正确做法是cat /dev/null /var/lib/docker/containers/容器ID/容器ID-json.log用cat清空而非rm保留文件句柄Docker才不会报错。别问我怎么知道的我吃过这个亏直接rm了log文件之后容器还活着但日志输出断了最后只能重启容器恢复。5.5 Docker命令突然找不到容器还有一类问题属于Docker数据目录出问题导致的异常。比如你执行docker ps -a发现之前的容器不见了但磁盘上还有数据。这多半是data-root配置被改过或者镜像仓库ID不匹配。第一种情况如果你在daemon.json里改过data-root但启动Docker时旧容器数据还在旧目录新目录是空的自然看不到容器。解决办法就是确认data-root路径并做数据同步。第二种情况docker-ce升级后有时会调整存储结构旧版容器数据挂在/var/lib/docker/containers新版还在用这个路径但如果你中间用过其他容器运行时比如containerd目录结构可能会乱。这种情况建议先备份数据再考虑用docker pull重新拉镜像或者直接重建容器。6. 部署完成后的第一件正事装好Docker只是万里长征第一步。我每次给新服务器装完Docker会立刻做三件事第一创建一个普通用户并加入docker组避免所有操作都用root完成。虽然root方便但万一误操作删了容器目录连后悔的机会都没有。普通用户加上docker组权限日常运维已经绰绰有余。useradd -m deploy usermod -aG docker deploy第二配置好daemon.json的日志切割和镜像加速这个前面说过不再重复但确实值得再强调一遍这个文件是你Docker环境稳定性的基石优先级最高。第三写一个简单的服务器信息记录文档把Docker版本、数据目录、挂载磁盘、容器端口、镜像加速器地址都记下来。以后每次排障都能省去一大半时间。根据我个人经验CentOS 7上部署Docker这件事本身难度不大真正难的是部署完之后的日常维护和故障排查。这篇教程里提到的那些配置尤其是日志切割、数据持久化、镜像加速建议你在第一次部署时就全部配好别等出问题再补救。毕竟容器的优势在于快速交付和一致性环境基础打好了后面跑任何应用都会顺手很多。
阅读完成 · 觉得有帮助?