Linux服务器Docker安装配置全攻略:从内核检查到生产环境优化
1. 项目概述为什么要在Linux上安装Docker如果你正在看这篇文章大概率是刚接触Linux服务器运维或者准备将手头的应用容器化。我当年第一次在CentOS上敲下yum install docker-ce命令时也以为这不过是个普通的软件安装。但踩过几次坑之后才明白在Linux上安装Docker远不止是执行几条命令那么简单它更像是在给你的服务器搭建一个全新的、更高效的“应用公寓”管理平台。简单来说Docker是一个开源的容器引擎。你可以把它理解为一个超级轻量级的虚拟机管理器但它比虚拟机更“抠门”也更快。虚拟机是“每家独栋别墅”有自己独立的操作系统内核、CPU、内存和硬盘虽然安全隔离好但搬家迁移麻烦资源占用也大。而Docker容器则是“精装公寓”所有“公寓”容器都共享大楼宿主机Linux的地基内核和水电系统硬件资源但每间公寓内部有自己独立的装修应用环境、家具依赖库和住户进程。这样一来部署一个应用就不再需要从零开始安装操作系统、配置环境而是直接“拎包入住”一个预先装好的标准化“公寓镜像”。那么在Linux上安装Docker到底解决了什么痛点我总结下来主要是三个环境一致性、资源利用率和交付效率。你再也不用在开发、测试、生产环境之间为“我本地是好的”这种问题扯皮一台物理机可以轻松跑几十个容器资源利用率大幅提升应用打包成镜像后交付和回滚就像复制文件一样简单。这篇文章我会以一个十年运维的视角带你从零开始在Linux上完成一次“教科书级”的Docker安装。我不会只给你命令我会告诉你每个命令背后的逻辑、每个配置项的作用以及我这些年积累下来的、文档里不会写的避坑技巧。无论你是刚入行的运维新人还是想尝试容器化的开发者跟着做一遍你不仅能装上Docker更能理解它。2. 安装前的深度准备不只是检查内核很多人安装失败第一步就错了。安装前的准备工作其重要性不亚于安装过程本身。这一步的核心是确保你的Linux系统是一块适合容器生长的“肥沃土壤”。2.1 系统与内核版本核查首先用uname -r查看内核版本。Docker CE社区版要求内核版本至少为3.10但我的经验是尽量使用4.x或更高版本的内核。3.10版本太老可能会遇到一些奇怪的网络或存储驱动问题。对于主流发行版如Ubuntu 20.04 LTS、CentOS 7.9/8、Debian 10其默认内核都满足要求。注意如果你使用的是CentOS 7且内核版本是3.10.0-xxx虽然能安装但在生产环境我强烈建议你升级到长期支持的内核版本如通过yum install kernel-lt安装ELRepo的长期支持内核。新内核在Overlay2存储驱动、cgroup v2支持等方面有更好的表现。接下来确认系统架构uname -m。x86_64即amd64是最主流且支持最好的架构。对于ARM架构如树莓派、华为鲲鹏服务器Docker也提供了官方支持但部分镜像可能不兼容需要寻找或自己构建ARM版本。2.2 关键依赖与存储驱动确认Docker运行依赖于几个关键的Linux内核特性我们必须手动检查而不是假设它们都已开启。cgroups控制组这是资源隔离的基石。检查/proc/cgroups文件只要不为空通常就没问题。namespaces命名空间这是进程、网络等隔离的基础。运行ls -la /proc/$$/ns/能看到一堆ns文件如net, mnt, pid等即表示支持。存储驱动支持这是最容易出问题的地方。Docker推荐使用overlay2存储驱动。检查内核是否支持grep overlay /proc/filesystems如果输出包含nodev overlay则支持。对于CentOS/RHEL还需要检查xfs文件系统的d_type支持这是overlay2必需的xfs_info / | grep ftype必须确保ftype1。如果是ftype0那么绝对不能使用overlay2否则会导致容器内文件删除等操作出现严重问题。此时只能退而求其次使用devicemapper但它的性能和稳定性远不如overlay2。2.3 彻底清理旧版本与冲突软件这是避免各种灵异问题的关键一步。如果你的系统上曾经通过yum install docker或apt install docker.io安装过老旧的“docker”包这通常是社区维护的旧版本称为docker.io或docker-engine必须彻底清除。# 对于基于Debian/Ubuntu的系统 sudo apt-get remove docker docker-engine docker.io containerd runc # 清除残留配置和数据谨慎操作会删除所有本地镜像和容器 sudo rm -rf /var/lib/docker sudo rm -rf /var/lib/containerd # 对于基于RHEL/CentOS/Fedora的系统 sudo yum remove docker \ docker-client \ docker-client-latest \ docker-common \ docker-latest \ docker-latest-logrotate \ docker-logrotate \ docker-engine sudo rm -rf /var/lib/docker sudo rm -rf /var/lib/containerd同时检查是否有其他容器运行时如Podman或冲突的端口监听老Docker可能占用了2375/2376端口。使用netstat -tlnp | grep :2375或ss -tlnp | grep :2375查看。3. 安装路径选择包管理器 vs 官方脚本准备好了系统环境接下来面临选择如何安装主流有两种方式通过操作系统的包管理器和使用官方提供的便捷脚本。它们各有优劣适用于不同场景。3.1 包管理器安装稳定与可控的首选这是生产环境的唯一推荐方式。通过添加Docker的官方APT或YUM仓库来安装好处是能无缝集成到系统的包管理体系中方便后续的升级、降级和依赖管理。对于Debian/Ubuntu系列核心步骤是添加Docker的GPG密钥和软件源。# 1. 更新apt包索引并安装必要的工具用于通过HTTPS使用仓库 sudo apt-get update sudo apt-get install \ ca-certificates \ curl \ gnupg \ lsb-release # 2. 添加Docker的官方GPG密钥。这是为了验证软件包的完整性。 sudo mkdir -p /etc/apt/keyrings curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg # 3. 设置稳定版仓库。注意将 $(lsb_release -cs) 替换为你的实际发行版代号如 jammy (Ubuntu 22.04)。 echo \ deb [arch$(dpkg --print-architecture) signed-by/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \ $(lsb_release -cs) stable | sudo tee /etc/apt/sources.list.d/docker.list /dev/null # 4. 更新源并安装 sudo apt-get update sudo apt-get install docker-ce docker-ce-cli containerd.io docker-compose-plugin实操心得第3步的仓库地址一定要匹配你的发行版。例如Ubuntu 22.04是jammy20.04是focal。不匹配会导致apt-get update失败。如果你不确定可以先去Docker官网文档查看对应发行版的仓库设置命令。对于RHEL/CentOS/Rocky Linux系列步骤类似但使用的是YUM仓库。# 1. 安装yum-utils包它提供yum-config-manager工具并添加仓库 sudo yum install -y yum-utils sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo # 2. 安装Docker引擎 sudo yum install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin注意事项如果你使用的是CentOS 8 Stream或Rocky Linux 8并且启用了powertools仓库可能会遇到与containerd.io包的依赖冲突。一个常见的解决方法是先安装containerd.io的特定版本或者暂时禁用powertools仓库。具体冲突信息会在yum install时给出需要根据报错灵活处理。3.2 官方脚本安装快速但不适合生产Docker提供了一个一键安装脚本get-docker.sh。它的优点是极其简单curl -fsSL https://get.docker.com -o get-docker.sh sudo sh get-docker.sh脚本会自动检测你的系统并完成所有安装步骤。但是我强烈不推荐在生产服务器上使用这种方式原因有三不可控脚本会自动安装最新版本你无法控制安装的版本号。生产环境需要版本稳定突然升级可能导致兼容性问题。不透明脚本在后台做了什么添加了哪些源安装了哪些额外的包你不完全清楚。这不符合生产环境“一切尽在掌握”的原则。难管理通过脚本安装的Docker后续升级无法通过系统包管理器进行管理起来更麻烦。这个脚本只适用于快速搭建测试、开发环境或者在一些非主流的Linux发行版上尝试安装。3.3 版本选择策略在通过包管理器安装时你可以选择特定版本。这对于生产环境至关重要。# 列出所有可用的版本 apt-cache madison docker-ce # Ubuntu/Debian yum list docker-ce --showduplicates | sort -r # CentOS/RHEL # 安装指定版本例如 24.0.9 sudo apt-get install docker-ce5:24.0.9-1~ubuntu.22.04~jammy docker-ce-cli5:24.0.9-1~ubuntu.22.04~jammy containerd.io # Ubuntu示例 sudo yum install docker-ce-24.0.9 docker-ce-cli-24.0.9 containerd.io docker-compose-plugin # CentOS示例我的建议是除非有明确需求否则不要盲目追求最新版本。选择一个比最新版晚1-2个小版本的稳定版例如当前最新是25.x你可以选择24.0.x并密切关注社区对该版本的反馈。4. 安装后的核心配置与优化安装完成执行sudo systemctl start docker和sudo systemctl enable docker后运行sudo docker run hello-world能成功只算成功了60%。剩下的40%在于配置和优化这直接决定了Docker在生产环境的稳定性和性能。4.1 非Root用户操作权限配置默认情况下执行Docker命令需要sudo权限。这很不方便也不安全相当于给了用户root权限。正确做法是将需要使用Docker的普通用户加入docker用户组。sudo groupadd docker # 如果docker组不存在则创建通常安装时会自动创建 sudo usermod -aG docker $USER操作后用户必须完全注销并重新登录或者启动一个新的shell会话组权限更改才会生效。之后该用户就可以直接运行docker ps等命令了。重要安全警告docker组的成员权限等同于root因为Docker守护进程以root身份运行。因此只应将可信用户加入此组。在多人使用的服务器上这是一个需要谨慎评估的安全风险点。4.2 镜像加速器与存储驱动配置国内从Docker Hub拉取镜像速度很慢必须配置镜像加速器。修改Docker守护进程的配置文件/etc/docker/daemon.json如果不存在则创建{ registry-mirrors: [ https://docker.mirrors.ustc.edu.cn, https://hub-mirror.c.163.com, https://mirror.baidubce.com ], exec-opts: [native.cgroupdriversystemd], log-driver: json-file, log-opts: { max-size: 100m, max-file: 3 }, storage-driver: overlay2, storage-opts: [ overlay2.override_kernel_checktrue ] }registry-mirrors: 配置国内镜像源可以配置多个Docker会按顺序尝试。exec-opts:native.cgroupdriversystemd: 这是关键配置。对于使用systemd作为初始化系统的Linux发行版如CentOS 7, Ubuntu 16.04必须将Docker的cgroup驱动设置为systemd以保持与主机系统cgroup管理器的一致避免出现资源管理的不稳定。这是很多新手会忽略但至关重要的一点。log-driver和log-opts: 配置日志驱动和滚动策略防止容器日志占满磁盘。storage-driver: 明确指定使用overlay2。storage-opts: 在某些旧内核上可能需要override_kernel_check来强制使用overlay2。修改配置后必须重启Docker服务使配置生效sudo systemctl restart docker。然后用docker info命令检查配置是否生效重点关注Registry Mirrors、Cgroup Driver和Storage Driver这几行。4.3 内核参数与资源限制调优默认的内核参数可能不适合高负载的容器环境需要进行调整。编辑/etc/sysctl.conf文件添加或修改以下参数# 提高系统最大文件描述符数量 fs.file-max 1000000 # 提高系统最大进程数 kernel.pid_max 1000000 # 提高系统最大用户进程数 kernel.threads-max 1000000 # 提高系统最大内存映射区域数量对于运行大量容器的场景很重要 vm.max_map_count 262144 # 优化网络性能启用TCP快速打开增大TCP缓冲区 net.core.somaxconn 65535 net.ipv4.tcp_max_syn_backlog 65535 net.ipv4.tcp_syncookies 1 net.ipv4.tcp_tw_reuse 1 net.ipv4.ip_local_port_range 1024 65535修改后执行sudo sysctl -p使配置立即生效。此外还需要调整系统的资源限制。编辑/etc/security/limits.conf文件在末尾添加* soft nofile 1000000 * hard nofile 1000000 * soft nproc 1000000 * hard nproc 1000000这个配置对所有用户生效提高了单个进程能打开的文件数和进程数上限对于运行数据库等需要大量连接的容器尤为重要。修改此文件后需要用户重新登录才能生效。5. 验证安装与运行第一个容器配置完成后我们需要进行全面的验证而不仅仅是运行hello-world。5.1 基础功能验证守护进程状态sudo systemctl status docker确保状态为active (running)。客户端-服务端通信docker version确保能同时输出Client和Server的版本信息这证明客户端能成功连接到守护进程。信息总览docker info仔细查看输出。确认Cgroup Driver: systemdStorage Driver: overlay2Registry Mirrors列表里有你配置的镜像地址。同时检查Total Memory、CPUs等信息是否正确识别了主机资源。运行测试容器docker run --rm hello-world。这个命令会从镜像仓库拉取hello-world镜像运行一个容器输出欢迎信息后自动删除容器--rm参数的作用。成功运行说明拉取镜像、创建容器、运行、清理整个链路都是通的。5.2 运行一个实用的容器让我们运行一个更实际的容器比如Nginx并测试端口映射和持久化存储。# 1. 拉取Nginx镜像 docker pull nginx:alpine # alpine版本更小巧 # 2. 运行一个Nginx容器将宿主机的8080端口映射到容器的80端口 # -d: 后台运行 # -p 8080:80: 端口映射 # --name my-nginx: 给容器起个名字 docker run -d -p 8080:80 --name my-nginx nginx:alpine # 3. 验证容器运行状态 docker ps # 应能看到my-nginx容器状态为Up # 4. 访问测试 curl http://localhost:8080 # 或者在浏览器访问服务器IP:8080应该能看到Nginx欢迎页。 # 5. 查看容器日志 docker logs my-nginx # 6. 进入容器内部用于调试 docker exec -it my-nginx /bin/sh # 进入后可以执行 ls, ps 等命令退出用 exit # 7. 停止并删除容器 docker stop my-nginx docker rm my-nginx通过这一系列操作你不仅验证了Docker的基本功能还实践了最常用的几个命令pull,run,ps,logs,exec,stop,rm。5.3 数据持久化测试容器本身是无状态的删除后数据就没了。持久化数据需要用到“卷”Volume或“绑定挂载”Bind Mount。# 创建一个数据卷 docker volume create my-data # 运行一个容器使用这个数据卷挂载到容器内的 /app/data 目录 docker run -d --name test-vol -v my-data:/app/data alpine tail -f /dev/null # 进入容器在挂载点创建文件 docker exec -it test-vol sh cd /app/data echo This data will persist test.txt exit # 删除容器 docker rm -f test-vol # 再运行一个新容器挂载同一个数据卷 docker run -d --name test-vol2 -v my-data:/app/data alpine tail -f /dev/null docker exec -it test-vol2 sh cat /app/data/test.txt # 应该能看到之前创建的文件内容 exit docker rm -f test-vol2 # 清理数据卷可选 docker volume rm my-data这个测试证明了数据卷独立于容器的生命周期是实现数据持久化的标准方式。6. 生产环境进阶配置考量如果你准备将安装了Docker的服务器用于生产环境那么还有一些更深层次的配置需要考虑。6.1 日志与存储目录迁移默认情况下Docker的所有数据包括镜像、容器、卷都存放在/var/lib/docker日志在/var/log/containers等位置。如果系统根分区/空间不大很容易被撑满。最佳实践是将这些目录迁移到大容量分区。假设我们有一个单独的大容量分区挂载在/data下。停止Docker服务sudo systemctl stop docker复制数据sudo rsync -avz /var/lib/docker/ /data/docker/备份原目录并创建软链接或修改配置sudo mv /var/lib/docker /var/lib/docker.bak sudo ln -s /data/docker /var/lib/docker或者更推荐的方式是直接修改Docker的启动参数指定数据根目录。编辑/etc/docker/daemon.json添加{ data-root: /data/docker }这种方式比软链接更清晰、更可控。重启Docker并验证sudo systemctl start dockerdocker info | grep Docker Root Dir确认路径已更改。同样的方法可以用于容器的日志目录通过配置log-driver的path选项或者使用系统的日志服务如journald来集中管理容器日志。6.2 网络模式与安全加固Docker默认创建bridge、host、none三种网络。生产环境中对于需要复杂网络拓扑的应用建议使用自定义的桥接网络而不是默认的bridge。# 创建一个自定义桥接网络并指定子网和网关 docker network create --driver bridge --subnet172.20.0.0/16 --gateway172.20.0.1 my-app-net # 运行容器时指定网络 docker run -d --name app1 --network my-app-net nginx:alpine docker run -d --name app2 --network my-app-net nginx:alpine # 此时app1和app2可以通过容器名直接互相通信如 ping app2自定义网络提供了更好的隔离性和可管理性比如可以方便地配置网络策略。安全加固方面除了前面提到的谨慎管理docker用户组外还需注意启用内容信任在daemon.json中设置content-trust: true可以确保只拉取经过签名的官方镜像。限制容器能力使用--cap-drop和--cap-add来精细化控制容器拥有的Linux能力遵循最小权限原则。例如运行一个Web服务容器可以去掉所有能力只添加NET_BIND_SERVICE绑定特权端口。设置用户命名空间这是一个高级功能可以映射容器内的root用户到宿主机的一个非root用户提供更强的隔离。但配置较为复杂需要修改/etc/subuid和/etc/subgid并在daemon.json中配置userns-remap。6.3 监控与维护安装完成后需要建立监控和维护机制。资源监控使用docker stats命令可以实时查看所有容器的CPU、内存、网络IO、磁盘IO使用情况。对于生产环境需要集成到PrometheusGrafana等监控体系中使用cAdvisor或node-exporter来收集Docker和主机指标。日志收集如前所述配置合理的日志驱动和滚动策略。对于集中式日志管理可以使用json-file或journald驱动然后由Fluentd、Logstash等日志收集器抓取并发送到Elasticsearch。定期清理Docker运行久了会产生很多停止的容器、无用的镜像none、悬空的卷和网络占用磁盘空间。可以定期执行清理命令# 删除所有已停止的容器 docker container prune -f # 删除所有未被任何容器引用的镜像悬空镜像 docker image prune -f # 删除所有未被使用的卷 docker volume prune -f # 删除所有未被使用的网络自定义网络慎用 # docker network prune -f可以将这些命令加入crontab定时执行。7. 疑难杂症与深度排错指南即使按照最标准的流程操作你也可能会遇到问题。这里我总结了一些最常见的“坑”及其解决方法。7.1 安装与启动类问题问题一Failed to start docker.service: Unit docker.service is masked.这通常是因为系统里存在多个冲突的Docker包或者之前用其他方式安装失败导致的。解决方法是“解掩码”并重新安装。sudo systemctl unmask docker sudo systemctl unmask docker.socket # 然后彻底卸载旧版本再重新安装问题二docker: Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?这是最经典的问题。意味着Docker守护进程没有运行或者当前用户没有连接权限。检查守护进程sudo systemctl status docker。如果没运行尝试sudo systemctl start docker并查看日志sudo journalctl -u docker.service。检查socket文件权限ls -la /var/run/docker.sock。其所属组应为docker。如果当前用户不在docker组就会报此错误。请确保已执行usermod -aG docker $USER并重新登录。检查环境变量某些情况下可能需要设置DOCKER_HOST环境变量但默认使用Unix socket时不需要。问题三Error response from daemon: failed to create shim task: OCI runtime create failed: ...或Your kernel does not support cgroup swap limit capabilities这类错误通常与cgroup或内核参数有关。确保已按照前文配置了native.cgroupdriversystemd。对于CentOS/RHEL编辑/etc/default/grub或/etc/sysconfig/grub在GRUB_CMDLINE_LINUX行末尾添加cgroup_enablememory swapaccount1然后执行sudo grub2-mkconfig -o /boot/grub2/grub.cfg并重启。这是为了启用内存和交换空间的cgroup支持。7.2 镜像拉取与容器运行类问题问题四Error response from daemon: Get https://registry-1.docker.io/v2/: net/http: request canceled while waiting for connection (Client.Timeout exceeded while awaiting headers)这是典型的网络问题无法连接到Docker Hub。首选方案确认/etc/docker/daemon.json中的registry-mirrors已正确配置国内镜像加速器并重启了Docker服务。检查网络ping registry-1.docker.io看是否能通。如果不通检查服务器的DNS配置/etc/resolv.conf和防火墙是否放行了443端口。临时方案如果只是拉取特定镜像可以尝试使用国内镜像站的完整地址如docker pull registry.cn-hangzhou.aliyuncs.com/library/nginx:alpine。问题五docker run提示Ports are not available或address already in use宿主机上的端口已被其他进程占用。使用ss -tlnp | grep :端口号或netstat -tlnp | grep :端口号查找是哪个进程占用了端口然后停止该进程或为Docker容器选择另一个端口。问题六容器内应用无法连接到外部网络如数据库或其他容器这通常是容器网络配置问题。检查容器使用的网络模式docker inspect 容器名 | grep NetworkMode。如果使用默认的bridge网络容器之间需要通过IP地址通信或者使用--link已废弃或自定义网络。检查宿主机的防火墙iptables或firewalld是否阻止了容器网络。Docker会自动配置iptables规则但有时firewalld会干扰。可以尝试临时停止firewalld (sudo systemctl stop firewalld) 测试如果问题解决则需要为firewalld添加Docker所需的zone和规则。7.3 性能与资源类问题问题七容器内磁盘IO或性能异常缓慢首先检查存储驱动。使用docker info | grep Storage Driver确认是overlay2。如果使用的是devicemapper且在循环设备上性能会极差必须迁移到overlay2这需要备份并重建/var/lib/docker目录操作复杂建议在新环境直接规划好。问题八Cannot kill container ...: Unknown error after kill: docker-runc did not terminate sucessfully这通常是容器进程僵死或进入不可中断睡眠状态D状态。此时docker stop和docker rm -f都无效。首先尝试sudo systemctl restart docker重启守护进程看是否能释放。如果不行找到容器的进程在宿主机上的PIDdocker inspect --format {{.State.Pid}} 容器名。尝试向该进程发送SIGKILL信号sudo kill -9 PID。如果进程还在可能是内核bug或存储驱动死锁。终极方法是重启宿主机。为了避免这种情况务必使用稳定的内核和推荐的overlay2存储驱动。安装和配置Docker是一个系统工程从系统准备、安装选型、细致配置到生产调优和故障排查每一步都需要理解其背后的原理。我的经验是在测试环境多尝试、多破坏把可能遇到的坑都踩一遍形成自己的排查清单。这样当你面对生产环境时才能从容不迫。记住稳定的Docker环境是容器化应用的基石这块基石打得越牢上层建筑才能越稳固。

相关新闻