ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

CentOS 7安装Docker完整指南:从环境检查到避坑实践

CentOS 7安装Docker完整指南:从环境检查到避坑实践 CentOS 7 上装 Docker听起来是十分钟搞定的事真上手你会发现坑都藏在细节里。这几年不管是帮人远程排查还是自己折腾服务器我遇到最多的问题几乎都发生在“CentOS 7 Docker”这个组合上。很多人拿到的都是现成命令复制粘贴完发现 docker 起不来、socket 连不上、镜像拉不下来然后就开始怀疑人生。这篇教程我会把 centos7 安装 docker 的全过程拆开讲不光给命令还会说清楚每步在干什么、为什么这么干、哪些地方容易炸。无论你是刚接触 Linux 的小白还是准备在公司老服务器上把业务容器化的运维同学这篇文章都可以当一份能直接照着抄的作业。它的内容不依赖任何第三方平台你在自己的服务器上跟着操作即可。我们先从原理讲起再逐步走到实战部署中间会穿插我实际踩过的坑和排查思路。1. 安装前先把这几件事想明白1.1 先确认你手里的 CentOS 7 到底是个什么状态很多教程上来就让你敲 yum install根本不提前置检查。我自己吃过亏的是拿到一台“号称 CentOS 7”的机器结果一查是 CentOS 7 最小化安装连 yum 源都是坏的更离谱的是内核版本停在 3.10.0-327Docker 装上去之后 overlay2 存储驱动一直报错。所以第一件事是先在终端里确认系统信息和内核版本cat /etc/redhat-release uname -r正常情况下你会看到类似这样的输出CentOS Linux release 7.9.2009 (Core) 3.10.0-1160.114.2.el7.x86_64CentOS 7 的默认内核是 3.10.x这个版本和 Docker 本身兼容但要注意CentOS 7 官方的系统维护周期在 2024 年 6 月已经结束了。也就是说它不会再收到常规的安全更新和内核补丁。针对这种情况我的建议分两种如果这是内网隔离环境里的老应用服务器继续使用 CentOS 7 还说得过去如果是要暴露到公网的业务机器建议你谨慎评估要么尽快规划迁移要么至少要保证 Docker 版本和镜像内部依赖独立升级不要把鸡蛋全放在一个系统包里。继续检查 CPU 架构和磁盘空间uname -m df -hx86_64 架构自然没问题如果是 aarch64ARM 架构甚至像龙芯、飞腾这类非 x86 平台官方 docker-ce 源里往往没有对应包你需要另外找对应架构的 rpm 包或直接用容器镜像来替代这一步别忽略了。内存建议至少 2GBDocker 本身不挑但跑容器时太小的内存容易触发 OOM到时排查起来很头疼。1.2 Docker 不是单一软件而是一整套组件的协作新手最容易混淆的一点是以为 Docker 就是一个叫 docker 的软件包。实际上官方仓库会拆成好几个包各干各的活docker-ceDocker 守护进程本体dockerd负责管理镜像、容器、网络、数据卷是核心服务。docker-ce-clidocker 命令行工具就是你敲 docker ps、docker run 时调用的客户端它会通过 socket 和 dockerd 通信。containerd.io容器运行时负责真正创建和运行容器进程。早期 Docker 直接管理 runc后来把底层拆给了 containerd再往上才是 dockerd。docker-buildx-pluginBuildKit 构建插件用来做镜像构建。docker-compose-plugindocker compose 子命令的插件用来编排多容器。安装的时候这几个包通常会一起装上但理解它们的边界很有必要。比如你执行 docker logs 时日志流是先经过 dockerd 再交给 containerd 的你执行 docker exec 进容器时其实最终是 runc 在操作进程。以后排查性能问题必须知道是哪一层出的故障。1.3 版本选择别盲目追最新Docker 官方仓库分 stable、test 和 nightly 三个通道我们只用 stable。但 stable 里也有大量版本号比如 20.10.x、23.0.x、24.0.x一直到 26.x 等。CentOS 7 这个环境比较特殊它的内核停留在 3.10systemd 停留在 219很多 Docker 新特性依赖内核和 systemd 的新能力所以并不是越新的 Docker 就越适合它。我在 CentOS 7 上长期跑过 20.10.21、23.0.6整体都算稳定。如果你追求省心我建议指定一个大版本安装而不是装 latest避免某天 yum update 时把 Docker 直接升级到新版本结果和你现有的内核不匹配。如何查看仓库里有哪些可用版本安装完 yum-utils 后执行yum list docker-ce --showduplicates | sort -r输出里会列出版本号安装时这样指定sudo yum install -y docker-ce-23.0.6 docker-ce-cli-23.0.6 containerd.io版本号后面跟 .el7 表示这个 rpm 包是基于 RHEL 7 系列编译的也适用于 CentOS 7。2. 环境清理与软件源准备2.1 干掉系统里残留的旧版 Docker很多服务器不是干净的之前可能为了图方便装过旧版 docker、docker-engine、docker-common或者用 yum 装过 docker.io这通常是 Ubuntu 系叫法但 CentOS 上也可能有遗留。这些旧包和新版 docker-ce 的目录、服务名、配置文件很可能冲突轻则安装报错重则装完无法启动。执行下面这串命令把不相关的旧包全部清理掉sudo yum remove docker docker-client docker-client-latest docker-common docker-latest docker-latest-logrotate docker-logrotate docker-engine如果系统提示没有这些包那就说明是干净的这是好消息。注意这个命令不会删除 /var/lib/docker 目录下的现有镜像和容器数据。如果你确认旧数据不要了可以手动清理sudo rm -rf /var/lib/docker这一步一定要谨慎删了就真的没了。迁移数据前最好先把镜像 save 出来或推送到私有仓库。2.2 安装 yum 工具链和必要依赖CentOS 7 默认带的 yum 工具比较有限我们需要额外装几个包sudo yum install -y yum-utils device-mapper-persistent-data lvm2这三个包分别起什么作用yum-utils 提供 yum-config-manager 命令用来添加和管理 yum 仓库device-mapper-persistent-data 是设备映射器的元数据管理工具以前 Docker 的 devicemapper 存储驱动依赖它现在虽然默认用 overlay2但装上以防万一lvm2 是逻辑卷管理工具如果你打算把 Docker 数据目录放到单独的逻辑卷上或者磁盘分区调整它会用到。2.3 配置 docker-ce 软件源这里要特别注意命令顺序。先把官方仓库配置加上sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo执行之后系统会下载一个 docker-ce.repo 文件放到 /etc/yum.repos.d/ 目录。如果想确认是否生效可以查看cat /etc/yum.repos.d/docker-ce.repo仓库内容里会包含 docker-ce-stable、docker-ce-test、docker-ce-nightly 三段。正常保留 stable 就够了。但如果你的服务器访问 docker 官方源很慢或者反复超时可以替换成国内镜像站。做法是先添加官方 repo然后把 repo 文件里的地址替换成镜像站地址sudo sed -i s|download.docker.com|mirrors.aliyun.com/docker-ce|g /etc/yum.repos.d/docker-ce.repo替换完成后建议先清理一下 yum 缓存重新生成sudo yum makecache fast这一步不复杂但直接决定你后面下载 rpm 包的速度和成功率生产服务器上尤其值得做。3. 安装 Docker 与启动验证3.1 通过 yum 正式安装仓库配置好了安装就很直接sudo yum install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin这里我直接装上了 buildx 和 compose 插件都是平时高频使用的工具。如果你只是想在机器上跑一个简单容器可以只装前三个包但装上后面两个也不会有什么额外负担。安装过程中如果提示依赖冲突最常见的是 container-selinux 版本太低。docker-ce 的 rpm 包要求 container-selinux 的版本在 2.107 以上。解决办法是先升级它sudo yum install -y container-selinux然后再执行 Docker 的安装命令。另外有些精简版服务器连 epel-release 都没装偶尔也会导致依赖解析失败。可以先安装 epelsudo yum install -y epel-release这个不是必须的但装了之后 yum 可用的包更全。3.2 脚本安装与离线安装什么场景才用得上除了 yum 仓库安装还有两种常见方式我说一下它们的适用场景。官方安装脚本方式curl -fsSL https://get.docker.com | sh这个脚本本质上也是帮你配置仓库然后安装适合快速测试但我个人不建议在核心生产服务器上直接管道给 sh。因为它会帮你自动添加源并安装 latest 版本版本不受控如果环境特殊脚本突然失败排查起来反而麻烦。比较适合的场景是一次性测试机、临时开发环境。离线安装方式适合严格的内网隔离环境。思路是找一台同样架构、同样系统版本的能联网机器用 yumdownloader 把依赖包全部下载下来再拷贝到内网机器上手动安装sudo yumdownloader docker-ce docker-ce-cli containerd.io --resolve --destdir/tmp/docker-rpm然后把 /tmp/docker-rpm 下的所有 rpm 文件拷到内网机器执行sudo rpm -ivh /tmp/docker-rpm/*.rpm注意 --resolve 参数是让 yum 把依赖包也一并下载这种方案对离线环境特别重要。下载前在联网机器上最好先 yum makecache确保能拿到最新的依赖列表。3.3 启动 Docker 并做基础验证安装完成后先不要急着拉镜像按顺序执行sudo systemctl start docker sudo systemctl enable docker sudo systemctl status docker第一行是启动服务第二行是设置开机自启第三行是查看服务状态。如果看到 active (running) 就说明守护进程已经正常起来了。再用 docker version 和 docker info 验证客户端和服务端版本是否匹配docker version如果输出分成了 Client 和 Server 两部分并且 Server 的版本号正常显示说明客户端到守护进程的链路是通的。这里要留意只有 Client 部分没有 Server 部分通常是守护进程没起来或者权限有问题。最后跑一个官方测试镜像docker run hello-world这个命令会从 Docker Hub 拉取 hello-world 镜像并创建一个临时容器能正常输出 “Hello from Docker!” 就说明整个 Docker 环境已经可用了。4. 安装完成后的关键配置4.1 配置镜像加速器解决拉镜像慢的老大难docker run 拉取镜像时如果不做任何配置默认走 Docker Hub。国内服务器拉大镜像经常慢到怀疑人生。解决办法是编辑 Docker 守护进程配置文件 /etc/docker/daemon.json添加 registry-mirrors 配置。这个文件默认不存在需要自己创建sudo mkdir -p /etc/docker sudo tee /etc/docker/daemon.json -EOF { registry-mirrors: [ https://docker.m.daocloud.io, https://dockerproxy.com ], exec-opts: [native.cgroupdriversystemd], log-driver: json-file, log-opts: { max-size: 100m, max-file: 3 }, storage-driver: overlay2 } EOF这里我直接把存储驱动、日志限制、cgroup 驱动也一起配上了。有小概率你遇到一个不稳定的公共镜像加速地址可以在网上搜当前可用的公共 registry mirror但注意要选可信的来源不要随便填一个来历不明的地址毕竟它会间接控制你拉取镜像的内容。配置完后重启 Docker 使配置生效sudo systemctl daemon-reload sudo systemctl restart docker用 docker info 可以确认配置是否生效输出里如果有一行 Registry Mirrors并列出地址就说明成功了。4.2 让普通用户也能执行 docker 命令默认情况下docker 命令需要 root 权限因为它是通过 /var/run/docker.sock 这个 socket 和守护进程通信的而这个 socket 的权限只对 root 开放。每次都输 sudo 很烦更合理的方式是创建一个 docker 用户组把使用 Docker 的用户加入组里sudo groupadd docker sudo usermod -aG docker $USER执行完 usermod 后必须重新登录终端或者执行 newgrp docker用户组信息才会刷新。之后你就不需要加 sudo 了。但这里有个安全细节必须提醒把用户加入 docker 组等同于把这个用户变成 root 的等价物。因为用户可以通过挂载宿主机目录的方式操作宿主机上的任意文件甚至直接修改 /etc/shadow。所以docker 组里只应该放你信任的运维账号普通员工账号不要随意加进去。4.3 日志和数据目录提前规划能省不少事Docker 默认把容器数据放在 /var/lib/docker包括镜像层、容器层、数据卷、网络配置。如果你的根分区不大这个目录很快会被撑满。建议在安装前就用数据盘单独挂载sudo mkdir /data sudo mount /dev/vdb1 /data然后通过修改 daemon.json 里的>{ data-root: /data/docker }改完后同样要重启 Docker。数据目录迁移这件事最好在安装初期就做因为一旦你已经拉了大量镜像迁移过程就需要先导出再导入麻烦得多。5. 上手试一下从跑容器到打包应用5.1 用一条命令部署 Nginx环境配置好后我们来真实跑一个业务场景启动一个 Nginx 容器。docker run -d --name my-nginx -p 8080:80 --restart unless-stopped nginx逐段解释一下-d 表示后台运行容器--name my-nginx 给容器起个名字方便后续管理-p 8080:80 把宿主机的 8080 端口映射到容器内的 80 端口--restart unless-stopped 设置容器退出后的重启策略只要不是手动 stop 的机器重启或容器异常退出都会自动拉起nginx 是镜像名如果不写版本号默认拉取 latest 标签。执行完后用 docker ps 看容器状态再用 curl 验证服务是否真的通了curl 127.0.0.1:8080能看到一堆 Nginx 默认欢迎页 HTML就说明容器已经正常对外提供服务了。如果这时候宿主机有防火墙记得先放行 8080 端口sudo firewall-cmd --add-port8080/tcp --permanent sudo firewall-cmd --reloadCentOS 7 默认用的是 firewalld不开放端口的话从机器外部是访问不通的。5.2 写一个 Dockerfile把本地应用打成镜像跑官方镜像只是第一步真实项目中更多场景是把我们自己的应用打包成镜像。我以最简单的 Python Flask 应用为例项目目录结构长这样/mnt/app ├── app.py └── requirements.txtapp.py 内容from flask import Flask app Flask(__name__) app.route(/) def index(): return hello dockerrequirements.txt 内容flask2.3.3然后在同一目录下创建 DockerfileFROM python:3.9-slim WORKDIR /app COPY requirements.txt . RUN pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple COPY app.py . EXPOSE 5000 CMD [python, app.py]构建镜像cd /mnt/app docker build -t my-flask-app:v1 .构建过程中每一行 Dockerfile 指令都会生成一个镜像层RUN pip install 那一层耗时最长因为它要下载依赖包。平时我优化构建速度的小技巧是先把 requirements.txt 复制进去并安装依赖再复制应用代码这样代码变更时依赖层能被缓存不会每次都重复下载。运行docker run -d --name flask-app -p 5000:5000 my-flask-app:v1 curl 127.0.0.1:5000看到 hello docker 就说明应用容器跑通了。5.3 用 docker compose 管理多容器应用单容器还好一旦涉及多个服务比如 Nginx 加 Redis就不建议一个个 docker run 了。这里用 docker compose 来统一管理。创建一个 docker-compose.ymlservices: web: image: nginx:1.24 ports: - 80:80 restart: unless-stopped redis: image: redis:7.2 ports: - 6379:6379 restart: unless-stopped启动docker compose up -d docker compose psdocker compose 的好处是整个服务栈可以用一个文件描述清楚新同事接手时看一眼就知道系统由哪几个容器组成新人上手成本大大降低。以后要停掉整个服务栈一条 docker compose down 就全搞定。6. 常见问题排查与避坑记录6.1 docker: Cannot connect to the Docker daemon这个报错出现频率最高几乎占了 Docker 问题的一半。执行 docker ps 时报错信息通常是Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?排查顺序按照下面这几步走systemctl status docker 看服务状态如果没有 active (running)可能是服务没起来journalctl -u docker -n 100 看 Docker 最近 100 条日志重点找 error、failed 字样如果服务在运行但 client 连不上检查 /var/run/docker.sock 是否存在权限是否是 srw-rw---- root docker如果命令前面没加 sudo 而当前用户也不在 docker 组也会出现这个报错这时用 sudo docker ps 试一下就能区分是权限问题还是服务问题。6.2 启动 Docker 时报 iptables 相关错误CentOS 7 下比较典型的报错是iptables failed: iptables --wait -t nat -A DOCKER -p tcp -d 0/0 --dport 8080 -j DNAT --to-destination 172.17.0.2:80 ...这个错误多半是 Docker 需要的 iptables 链被 firewalld 或之前残留的防火墙规则干扰了。最简单的处理方式是重启 firewalld 和 Dockersudo systemctl restart firewalld sudo systemctl restart docker如果还不行检查 /etc/sysconfig/network 里是否有异常配置有些环境在/etc/sysctl.conf里把 ip_forward 设成了 0容器网络就会失效。6.3 cgroup 驱动不匹配Docker 和 kubeadm 打架如果你在这台机器上后面还要部署 Kubernetes会遇到 cgroup 驱动不匹配的问题。Kubernetes 的 kubelet 在 CentOS 7 上默认使用 systemd 作为驱动而 Docker 默认是 cgroupfs。两者不一致时kubelet 会报failed to run Kubelet: failed to run kubelet: unknown runtime docker或者状态一直是 NotReady。解决办法就是在 daemon.json 里加上{ exec-opts: [native.cgroupdriversystemd] }然后重启 Docker。这个配置建议从一开始就加上即使现在不装 Kubernetes以后也不会被它卡住。6.4 overlay2 存储驱动报错文件系统不支持 d_type有台老服务器用 xfs 格式化的根分区Docker 启动时直接报failed to mount overlay: operation not permitted或者提示 overlay2 不支持 d_type。这是因为 xfs 在格式化时没有开启 ftype1 参数。最稳妥的方案是把 Docker 的数据目录迁移到一个支持 d_type 的文件系统上或重新用下面参数格式化并配合数据迁移mkfs.xfs -n ftype1 /dev/vdb1如果你不想动文件系统也可以在 daemon.json 里暂时把存储驱动改成 vfs但那只是逃避问题vfs 镜像占用空间大、性能损耗明显不推荐用于生产。6.5 容器时间不对和日志爆炸容器默认使用 UTC 时区如果你直接用官方 nginx、mysql 镜像容器日志的时间和宿主机可能相差 8 小时。解决办法是在 docker run 时挂载宿主机的时区文件docker run -d --name my-nginx -v /etc/localtime:/etc/localtime:ro nginx日志爆炸则是另一个隐蔽问题。有些容器本身就高频输出日志默认 json-file 驱动不加限制的话/var/lib/docker/containers 目录会一直膨胀。我已经在前面建议配上了 max-size 和 max-file这里再强调一次{ log-driver: json-file, log-opts: { max-size: 100m, max-file: 3 } }这样单个容器最多保留 3 个 100MB 的日志文件超过就滚动清理不会无限增长。6.6 再分享一个习惯定期清理无用 Docker 资源Docker 用久了机器上会堆积大量悬空镜像dangling images、停止的容器、未使用的网络和构建缓存。执行 docker system df 可以看占用情况docker system df清理悬空镜像和停止容器docker system prune -f这个命令会删除所有停止的容器、没有被容器使用的网络、悬空镜像和构建缓存。如果有暂时停着但后面还要用的容器建议先确认再执行。谨慎一点的做法是只清理构建缓存docker builder prune -f从最开始安装到现在跑通 Nginx、打包本地应用、排完几个典型问题整套流程已经走了一遍。我个人在实际操作中的体会是在 CentOS 7 上装 Docker真正的难点从来不在于命令本身而在于你对这台机器底细的了解程度。文件系统支不支持 overlay2、防火墙规则干不干净、端口有没有被占用、内核版本跟最新 Docker 相不匹配这些提前确认过安装过程就会非常顺滑。最后再分享一个小技巧装完 Docker 后建议把 /etc/docker/daemon.json 和 docker version 的输出备份一份以后排查问题时能快速对照出环境是不是被人动过手脚这会省掉很多无谓的返工。
返回列表