ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Docker核心概念详解与CentOS安装配置实战

Docker核心概念详解与CentOS安装配置实战 说真的接触Docker这么多年我最大的感受就是它是一个“用一次就回不去”的工具。尤其是在CentOS这种服务器环境上以前部署一个应用要装依赖、调环境变量、处理端口冲突折腾半天现在一个镜像、一条run命令三十秒跑起来换机器也不怕。这篇文章是“Docker 从入门到实战”系列的第一篇我会把Docker 核心概念和CentOS 下的安装配置这两块一次讲透适合刚接触容器、想在服务器上把Docker跑起来的新手也适合那些已经装过但没搞明白原理的人。我会尽量不绕弯子用实际踩坑经验加命令示例来讲。你不需要提前懂Kubernetes、不需要懂Cgroup只需要一台能联网的CentOS机器和基本的Linux命令行操作能力。读完这篇文章你会搞懂镜像和容器到底是什么关系、CentOS版本该怎么选、yum源怎么配、Docker装完之后怎么验证、启动失败和网络不通这类问题怎么排查。不光是“照着敲能跑”而是“敲完知道为什么”。1. 先从核心概念说起镜像、容器、仓库是什么关系1.1 镜像不是安装包而是“文件系统快照启动配置”很多新手刚开始接触Docker最容易犯的错就是把镜像Image理解成类似tar.gz的安装包。其实不是。镜像是分层存储的只读模板它里面打包了完整的文件系统——包括操作系统的基础库、运行时、配置文件、环境变量以及你要运行的应用代码。但它本身不是一个“正在运行的程序”更像是一台电脑的硬盘克隆文件随时可以复制、分发、启动。举个例子你可以在网上找一个CentOS 7.9的基础镜像它里面就有完整的根文件系统bin目录、usr目录、lib库都在。你在这个基础上安装MySQL、装上PHP、写好配置然后通过commit或者Dockerfile把这一层一层的改动固化成一个新镜像。这个新镜像拿到任何一台装了Docker的机器上都能跑出一模一样的环境。这里有个关键特征镜像是分层的。Dockerfile里每一条指令生成一层底层镜像被多个上层镜像共享。所以拉取一个大型镜像时你可能会看到“Already exists”这样的提示说明这一层之前已经拉过了不需要重复下载。这也是Docker能省磁盘空间、能瞬间秒开多个容器的底层基础之一。理解这一点你会明白一个实操中的常见现象为什么同一个镜像启动的多个容器各自修改文件互不影响。因为容器启动时Docker会在镜像之上挂载一个可写层所有写入都发生在这一层底层镜像始终不变。一旦容器删除可写层跟着销毁就“一切归零”。1.2 容器是镜像的“运行实例”状态是临时的容器Container就是镜像运行起来之后的状态。你可以把它理解成“一个独立的、隔离的进程组”。隔离靠的是Linux内核的Namespaces资源限制靠的是Cgroups这两者正是容器和虚拟机最大的差异所在。虚拟机要多跑一个完整Guest OS容器则直接在宿主机内核上运行。这带来的好处有两个一是启动极快常规容器几百毫秒就能起来二是密度极高一台8G内存的服务器传统虚拟机可能只能跑两三台容器却能跑几十个实例。但同样的容器的隔离不如虚拟机彻底。内核是共享的如果宿主机的内核出问题所有容器都会受影响。所以生产环境一般会限制容器权限、配置Seccomp、只读挂载等防止容器内权限提升。容器状态是临时的这个真的很重要。容器一旦rm删除里面写入的所有数据都没了。所以做数据库这类有状态服务时必须挂载宿主机目录volume或者使用命名卷否则重启就丢数据。我见过不止一个人用Docker跑MySQL跑了两周然后一条docker rm把整个数据库删了数据全丢。这不是笑话是真实事故。后面讲安装配置时我会把这部分操作讲得更细。1.3 仓库就是镜像的“应用商店”默认是Docker Hub仓库Registry是存放和分发镜像的服务。你执行的docker pull命令默认去的是Docker Hub这是Docker官方维护的公共镜像仓库。里面有大量官方镜像比如centos、nginx、redis、mysql也有个人上传的镜像。为什么仓库重要因为拉镜像的速度和可达性基本决定了你使用Docker的体验。如果你直接连Docker Hub国内机器拉官方镜像通常不太理想几个G的大镜像动辄卡半天。解决方案一般是配registry mirror也就是镜像加速地址。这在下文第4节我会专门讲这部分配置好之后拉镜像速度能快一个量级。连上仓库之后你需要遵循一套命名规则镜像地址由仓库域名、命名空间、镜像名、标签组成。比如docker.io/library/nginx:1.24docker.io是仓库地址library是官方命名空间nginx是镜像名1.24是标签。实际操作中public仓库可以省略域名和命名空间直接nginx:1.24就能拉取。不理解这套命名规则你在配置私有仓库或者写Dockerfile时很容易蒙圈。核心小结镜像只读分层、容器临时可变、仓库负责分发。这三者的关系最通俗的类比是镜像等于“类”容器等于“实例”仓库等于“代码托管平台”。类定义了属性和方法实例是具体运行的对象而代码托管平台负责保存和分发你写好的类模板。2. CentOS环境的前期准备与版本选择2.1 到底选CentOS 7.9还是8 Stream我经常被问到一个问题教程里用的CentOS 7.9现在还能用吗该不该上8 Stream这事得掰开来说。CentOS 7.9是目前存量服务器中最常见的版本网上绝大多数运维文档、集群部署脚本都是基于7.x写的。虽然红帽官方已经宣布CentOS 7在2024年6月30日停止维护但实际生产环境里7.9的存量依然非常巨大老项目的稳定性依赖它。CentOS 8 Stream则是一个滚动发布版本跟随Fedora的节奏往前迭代不像7.9那样固定小版本。对于追求新内核、新特性的场景8 Stream能给你更新的工具链但同时意味着你的行为模式要跟着上游变化比如yum部分命令被dnf替代、仓库配置方式也有变化。如果你是为了跑Docker、跑K8s这类现代化服务8 Stream完全没问题如果你是为了兼容老业务、照搬老教程老老实实7.9更省心。从Docker的角度讲两种版本都能顺利安装区别主要在repo源名称和一些依赖包上。Docker官方提供的yum源叫做docker-ce.repo安装时会自动适配系统的major版本。官方目前仍然维护CentOS 7的Docker包支持CentOS 8的包也没问题。所以不用太纠结只要内核在3.10以上Docker都能跑起来。2.2 安装前必须确认三件事正式敲安装命令之前我先建议你花两分钟确认一下系统状态免得装到一半出幺蛾子。第一件事是看内核版本执行 uname -r。Docker对内核的最低要求是3.10CentOS 7默认内核是3.10.x够用CentOS 8一般是4.18或更高体验更好。内核版本过低时OverlayFS和某些网络功能会受限最好还是升级一下。第二件事是看系统位数必须64位。执行 uname -m 如果显示x86_64或者aarch64说明没问题。Docker本身早就不支持32位系统了你要是手里有台32位的旧机器别折腾Docker换个方案吧。第三件事是确认网络环境。Docker安装过程中要下载大量依赖安装完成之后还要拉镜像。如果服务器是内网的、或者出口路由受限你要提前准备好内网源或者离线rpm包。这里特别提醒一下很多人安装完Docker后发现docker pull一直卡住第一反应是代码问题其实十有八九是仓库网络问题。等下在第四节我会演示镜像加速怎么配置这里先打个预防针。命令汇总uname -r # 内核版本 uname -m # 架构 cat /etc/redhat-release # 系统版本2.3 防火墙和SELinux的取舍CentOS默认开着firewalld和SELinux这两个东西在传统应用上问题不大但和Docker碰撞时偶尔会给你添堵。最常见的情况是容器启动了端口映射也配了但宿主机外网就是访问不到。查了半天发现是firewalld拦截了。另一个情况是SELinux的布尔值没开导致容器挂载目录时没有权限报Permission denied。我不建议你彻底关闭SELinux除非是在测试环境。生产环境里更稳的做法是给特定端口放行。比如容器映射到宿主机8080端口就执行firewall-cmd --add-port8080/tcp --permanent firewall-cmd --reload如果Docker的网桥模式总是被防火墙干扰关闭firewalld也是一种临时解法但你自己要清楚风险。SELinux这边如果只是跑Docker可以设置容器相关布尔值来适配并不需要setenforce 0。把SELinux一关了之是很多人的习惯但真出了安全审计这个操作就是给自己埋雷。3. CentOS上安装Docker的完整实操3.1 配置yum源并安装docker-ce安装Docker的第一件事不是直接yum install docker而是先安装依赖工具并配置官方yum源。CentOS上最顺手的做法是用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这里有个细节如果你用的是阿里云、腾讯云这类国内镜像机器拉取download.docker.com不一定慢但也不是一直稳定。遇到这种情况可以直接把repo地址替换成国内云的Docker源比如阿里云的sudo yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo添加完repo之后不需要额外做什么yum会自动读取。接着执行sudo yum install -y docker-ce docker-ce-cli containerd.io这条命令会装好三个核心组件docker-ce是Docker守护进程和CLI主包docker-ce-cli是客户端命令集containerd.io是容器运行时负责实际创建和运行容器。早期Docker版本直接带containerd现在拆开了所以三个一起装不会错。安装过程中如果提示依赖冲突多半是你之前用别的源装过docker或者docker-selinux这时候建议先检查已有包rpm -qa | grep docker sudo yum remove -y docker docker-client docker-common注意这一步不要把已经存在的数据目录删掉/var/lib/docker里如果有旧数据卸载包会保留重新装上又能用。3.2 启动Docker服务并配置开机自启安装完成之后Docker并不会自动运行你还需要手动启动守护进程。CentOS 7、8都是用systemd来管理服务的sudo systemctl start docker sudo systemctl enable dockerstart是立即启动enable是把Docker加入开机自启列表。我强烈建议每次装完都顺手敲一下enable否则服务器重启之后Docker不会自动起所有依赖Docker的服务跟着全部挂掉。启动之后看一眼状态sudo systemctl status docker sudo docker versiondocker version会同时输出Client和Server两段信息。如果Server那段能正常显示版本号说明守护进程已经在跑了。如果只显示Client、Server是空说明服务没启动或者启动失败这时候要去翻日志sudo journalctl -xu docker.service对了CentOS 7上还需要注意一点如果你之前改过主机名、网络配置可能影响Docker网络初始化但一般不会导致服务起不来。真起不来时先看日志里是不是有“iptables”相关报错多半是防火墙或转发机制冲突。3.3 用hello-world和nginx验证安装效果服务跑起来后最经典的验证方式是跑一下hello-worldsudo docker run --name hello-test hello-world第一次执行时Docker会尝试从官方仓库拉取hello-world镜像。如果拉取成功并且控制台输出一段“Hello from Docker!”的说明文字恭喜你Docker的安装和运行链路已经通了。如果这一步卡住了八成是网络访问Docker Hub不畅。先别急着怀疑人生本节后面说到的镜像加速可以解决这个问题。拉取失败是网络问题不是Docker本身的问题。再进一步跑一个Nginx容器来验证端口映射sudo docker run -d --name nginx-test -p 8080:80 nginx:latest这里-d表示后台运行-p 8080:80表示把宿主机的8080端口映射到容器的80端口。运行之后用curl访问本机8080端口curl http://127.0.0.1:8080如果返回Nginx默认页面说明容器网络完全正常。你还可以用docker ps看到运行中的容器列表用docker logs nginx-test看Nginx日志。跑通这两个容器之后你的Docker环境在功能上就算完全可用了。4. 镜像加速配置与日常操作要点4.1 为什么需要配置镜像加速以及怎么配国内实机拉取Docker Hub官方镜像速度很不稳定尤其是大镜像经常出现拉一半断掉的情况。这是因为公共仓库的服务器物理位置在海外跨境网络链路复杂。这里说的不是需要用额外手段而是Docker官方提供了一种叫registry mirror的机制你配置一个国内可达的公共镜像仓库作为拉取代理Docker在pull时先访问这个镜像仓库它再去上游同步相当于帮你跑了一程。Docker的配置入口是/etc/docker/daemon.json。如果这个文件不存在就新建一个。内容如下{ registry-mirrors: [ https://docker.m.daocloud.io, https://dockerproxy.com, https://mirror.ccs.tencentyun.com ] }配置完以后重启Docker让配置生效sudo systemctl daemon-reload sudo systemctl restart docker这里提个醒如果daemon.json里还有其他配置比如data-root、exec-opts合并时千万别把原内容覆盖掉。网上很多教程只贴了registry-mirrors一段有人直接覆盖了配置结果Docker数据目录都被挪了把已有容器整得路径对不上。配置完成之后可以执行docker info看一眼Registry Mirrors那一段如果列出了你配置的地址说明生效了。4.2 Docker Desktop和Linux上直接装Docker的区别热搜词里很多人搜“Docker Desktop”这里顺便讲清楚。Docker Desktop是面向macOS和Windows的图形化工具它会在系统里虚拟一个轻量级Linux虚拟机再在虚拟机里跑Docker服务。好处是免去了你手动装Linux虚拟机的麻烦坏处是资源占用明显更高而且它对Windows系统有一项硬性要求必须开启CPU虚拟化VT-x/AMD-V。如果BIOS里没开启动时会报“virtualization support not detected”之类的错误。而你在CentOS服务器上直接安装的docker-ce是在原生Linux内核上运行的效率更高不需要任何虚拟机层。两者命令基本通用Docker Desktop只是多套了层壳。理解这一点很重要否则你很容易照着一个Windows教程在CentOS上操作发现一切对不上号。4.3 给当前用户授权免去每次sudo默认情况下执行docker命令需要root权限因为Docker守护进程的socket文件/var/run/docker.sock属于root用户。为了避免每条命令都加sudo可以把当前用户加进docker组sudo groupadd docker # 如果docker组不存在才需要 sudo usermod -aG docker $USER改完组之后要么重新登录要么执行newgrp docker切换当前会话否则组权限不生效。这步操作在生活中特别实用我日常开发时几乎从不打sudo docker都是直接docker ps。不过要提醒一句加入docker组等于变相获得了root权限因为Docker提供的能力可以让你挂载宿主机的任意目录。所以这个操作只建议在自己可控的机器上做共享机器上要谨慎。5. 常见安装与使用问题排查5.1 启动失败iptables、SELinux、存储驱动三板斧Docker启动失败是安装过程中最让人头疼的问题。我遇到过几类典型报错第一类是“Failed to start Docker Application Container Engine”日志里出现iptables相关字样。这通常是因为Docker需要修改宿主机的iptables规则但被SELinux或firewalld挡住了。排查思路很简单先看日志再定位冲突。临时解法是把firewalld关掉或者执行systemctl restart docker多试几次因为有时候是系统iptables服务先占用了规则表。第二类是SELinux报错表现为启动后容器无法挂载目录提示Permission denied。很多优化教程会教你setenforce 0但前面我也说了关闭SELinux是一招饮鸩止渴。更稳的方案是确认SELinux的容器相关策略放行。实在需要快速解决可以先用setenforce 0验证问题是否出在SELinux等明确了再决定后续策略。第三类是存储驱动相关英文日志里会出现“error creating overlay mount”。这种情况多见于内核版本较旧、或者文件系统不支持OverlayFS。CentOS 7早期内核确实有过这类坑解决办法是改用vfs存储驱动或者升级内核。在daemon.json里加一行“storage-driver”: vfs可以临时绕过但vfs效率低不推荐长期使用。最理想的情况是确保内核较新且系统盘是xfs或ext4基本就能用overlay2。下表是这三种错误的快速对照报错现象常见原因快速解法根本解法iptables相关报错firewalld或系统iptables规则冲突停掉firewalld并重启docker调整防火墙策略放行Docker网桥SELinux权限报错SELinux布尔值未放行setenforce 0临时验证配置容器适配SELinux策略overlay文件系统错误内核版本低或文件系统不支持临时切换vfs驱动升级内核、格式化分区为xfs/ext45.2 容器网络不通端口映射、网桥模式、防火墙网络不通的问题出现频率很高而且原因五花八门。最常见的是宿主机所有端口映射都访问不了比如用-p 8080:80启动容器curl 127.0.0.1:8080有响应但局域网其他机器访问不了宿主机IP。第一检查点就是firewalld有没有放行8080端口。第二检查点是系统是否开启了ip_forward执行sysctl net.ipv4.ip_forward检查是否为1如果是0编辑/etc/sysctl.conf加一行net.ipv4.ip_forward1再sysctl -p。另一种情况是容器内能通外网但容器和宿主机之间互相访问异常多发生在你手动指定了docker0网桥的IP段或者宿主机上存在多个网段冲突。这时候建议在daemon.json里重新指定bip参数比如“bip”: 192.168.56.1/24注意网段不要和现有网络冲突。还有一种很低级但常见的坑你在容器里跑了Nginx并且把网站的listen地址配成了127.0.0.1那么无论你怎么做端口映射宿主机访问都是失败的。因为容器内的127.0.0.1只指向容器自己。这种问题从Docker这边排查永远无解只有进容器看日志才会发现真相。所以遇到网络问题先docker logs看程序日志再看端口绑定最后才怀疑Docker网络配置。5.3 磁盘空间占用与基本清理Docker用久了/var/lib/docker目录会越来越大。镜像层层累积、多个容器叠加层、且悬空镜像dangling image堆积很容易把磁盘塞满。热搜词里的“centos扩容”也是这类问题的延伸。清理之前先看占用情况docker system df docker system df -vdocker system df能看到镜像、容器、本地卷、缓存这四类各占多少空间。然后根据情况选择清理命令docker system prune # 清理停止的容器、无用网络、悬空镜像 docker system prune -a # 更进一步把没有容器在用的镜像全删掉 docker volume prune # 清理未被使用的本地卷注意docker system prune -a是个危险命令。它会删除所有未被使用容器引用的镜像等你下次启动容器时又得重新拉取。如果你只是想清理缓存和悬空镜像不加-a就够了。我一般习惯先执行不带-a的prune然后再单独手动清理确定的镜像。磁盘空间还有一个老生常谈的点Docker默认的data-root在/var/lib/docker如果系统盘很小可以考虑把data-root挪到大容量数据盘上。改daemon.json里的data-root字段然后停Docker服务搬目录再启动。这条路径对新手来说重了点但只要数据盘挂载好一次操作能省掉以后很多扩容麻烦。5.4 常用命令速查与几条最实用的操作习惯安装配置完之后下面这张命令表可以帮你快速上手日常操作建议先收藏。需求场景命令示例说明查看所有运行中的容器docker ps加-a显示所有包括已退出的停止、删除容器docker stop 容器名 docker rm 容器名先停再删删了数据就没了查看容器日志docker logs -f 容器名-f是持续跟踪排错时必备进入容器内部docker exec -it 容器名 bash容器内必须有bash否则用sh查看镜像列表docker images查看本地所有镜像清理无用资源docker system prune安全、常用构建自定义镜像docker build -t 名字:标签 .Dockerfile所在目录执行最后分享几个我平时坚持的操作习惯第一启动容器时永远给container命名不命名的话Docker会生成一堆随机名字你根本分不清谁是谁第二挂载目录时用绝对路径并且在宿主机上先创建好目录避免Docker帮你创建出root属主的目录第三所有需要持久化的数据比如MySQL数据目录、配置文件一定要用卷或者挂载目录别丢在容器可写层里。这三条习惯能帮你避免掉绝大多数“用着用着出了问题”的破事。我在实际使用中最深的体会是Docker给你省下来的时间往往会在“不熟悉概念”这件事上还回去。所以这篇文章宁愿多花点篇幅讲清楚镜像、容器、仓库的关系也不建议大家拿到命令就直接复制粘贴。先把安装这一步走扎实把daemon.json弄明白把容器生命周期搞清楚后面的镜像构建、编排部署、CI/CD集成才会顺理成章。下一篇我会接着写镜像构建和Dockerfile编写的实战细节到时候我们继续聊。
返回列表