Linux运维必学:Docker与K8S入门到实战

Linux运维必学:Docker与K8S入门到实战 在Linux运维岗位的日常工作中环境部署、服务上线、故障恢复占用大量时间而Docker和K8S这两项技术恰好针对这三个环节做减法。Docker解决的是“应用和运行环境一起打包交付”的问题K8S解决的是“大量容器在多台服务器上如何调度、恢复、对外提供访问”的问题。对零基础入门者来说真正难的不是背命令而是先建立“镜像、容器、Pod、集群”这几层概念再用可复现的实战把知识串起来。下面按学习路线展开从Linux上安装Docker、跑通常见中间件到理解K8S集群、部署应用、排查故障最后给出一份针对运维岗位的练习路径。1. 先理解Docker和K8S在Linux运维中各自要解决什么问题很多零基础学习者会直接把“Docker”和“K8S”当成同一类东西其实它们是两个不同层级的工具。判断是否真的理解了它们可以用一个问题自测给你一台新服务器让你部署一个MySQL你会用Docker做给你十台服务器每台都跑几十个容器你还会只用Docker命令管理吗后者就是K8S的典型场景。1.1 容器化解决的是“环境一致性”问题在没有容器之前环境问题表现为三种形式。第一种是“本地能跑服务器跑不起来”。本地JDK版本、Node版本、依赖库都和服务器不一致部署一次需要人工核对一堆环境项。第二种是“这台能跑那块不能跑”。同一套代码部署到不同阶段环境底层系统版本不一样结果也不一样。第三种是“项目多了以后互相污染”。不同项目需要不同版本的Python、Java或MySQL装在同一台服务器上很容易冲突。Docker用镜像解决这个问题。镜像把代码、运行环境、依赖、配置写进一套可复现的模板启动容器就等于在独立隔离环境中运行这套模板。它实现的是操作系统级虚拟化容器共享宿主机内核但通过命名空间做进程、网络、文件系统隔离通过cgroups限制资源使用。换句话说容器不是轻量虚拟机容器里的进程本质上仍然是宿主机内核上的进程只是它看到的环境被隔离了。这个理解能解释很多现象。比如容器里没有systemd因为容器不需要管理宿主机服务容器里的PID 1是启动命令指定的主进程容器会在主进程退出后立即退出。学习阶段如果只记住docker run不理解“容器是进程”这点后面遇到“容器启动就退出”的问题时会非常难查。1.2 Docker与K8S的关系和区别可以用一个直观类比Docker是集装箱负责把货物打包、搬运、拆箱K8S是港口调度系统负责决定这些箱子放在哪个泊位、缺货时怎么补、哪条货船先出港。从技术上讲K8S是一个容器编排平台。它通过声明式配置描述应用的期望状态比如“我要运行3个副本”然后由控制器持续保证集群里的实际状态接近期望状态。Docker负责单个容器的运行和管理K8S负责一批容器在多节点上的调度、自动恢复、滚动更新和服务发现。两者不是替代关系而是分工关系。Docker构建出来的镜像是符合OCI标准的镜像K8S可以使用这类镜像。在实际技术栈中K8S节点上的容器运行时也不一定直接依赖Docker命令而是通过containerd等运行时执行镜像。对运维来说Docker侧重“交付和运行单位”K8S侧重“集群和治理能力”。可以从下表快速理解对比维度DockerK8S管理范围单台主机上的容器多台主机组成的集群核心对象镜像、容器、数据卷、网络Pod、Deployment、Service、Node是否负责调度不负责跨节点调度负责调度到合适的Node故障恢复单容器崩溃需要外部机制拉起控制器自动维护副本数量版本升级重建容器或替换镜像支持滚动更新和回滚1.3 零基础入门的主线先容器后编排再排障如果目标是“速通Linux运维”不要一上来就搭K8S集群那会同时踩到网络、证书、容器运行时、调度策略等多层问题。更稳的学习顺序是在Linux上安装Docker掌握镜像、容器、数据卷、端口映射。用Docker安装MySQL、Redis等常用中间件理解“容器不是虚拟机”。用Docker Compose编排多服务理解服务和依赖。搭建单节点的minikube或k3s先体验K8S的Pod、Deployment、Service。再用kubeadm搭多节点集群补上调度、网络、RBAC和监控。最后熟悉故障排查链路。每一阶段都解决一个明确问题。靠一条命令“速通”是不可能的但按这条主线通常可以在两到三周内建立完整认知。2. 准备环境先把一个可用的Docker装到Linux上很多教程直接给安装命令但实际安装时容易卡在系统版本、内核参数、仓库配置和镜像下载上。环境准备阶段花一点时间对齐后面可以少踩很多坑。2.1 环境要求系统版本、内核与学习环境选择Docker对Linux系统有一些基本要求。若使用虚拟机建议分配2核4G内存、20G以上磁盘若使用云主机选择Ubuntu 22.04 LTS或Rocky Linux 9这类仍在维护中的系统即可。参考环境要求如下系统常见版本内核要求学习建议Ubuntu / DebianUbuntu 22.04、24.04 LTS推荐内核5.x及以上最省心官方文档覆盖好CentOSCentOS 7.9内核3.10建议升级CentOS 7已停止维护新项目不建议选择Rocky / AlmaLinux9.x内核5.14可作为CentOS替代Windows / macOSWindows 10/11macOS依赖WSL2或虚拟化适合本机开发不作为生产环境这里有一个容易忽略的点如果在容器里跑K8S还需要确认两个内核模块overlay和br_netfilter。它们负责容器的存储驱动和网络流量转发。学习K8S前先确认系统是否支持这两项。2.2 Ubuntu上安装Docker的标准流程Ubuntu上最稳妥的方式是使用Docker官方apt仓库而不是直接apt install docker.io。官方仓库版本更新更及时也包含Compose插件。下面这段命令适用于Ubuntu 22.04 / 24.04sudo apt update sudo apt install -y ca-certificates curl gnupg lsb-release sudo install -m 0755 -d /etc/apt/keyrings curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg 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 sudo apt update sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin sudo systemctl enable --now docker这段命令做了四件事安装依赖工具、添加Docker官方GPG密钥、写入apt仓库地址、安装Docker本体及插件。其中docker-compose-plugin提供docker compose命令是一个较新的Capability比单独安装Python版Compose更省事。之所以要这样安装是因为操作系统的自带仓库往往版本滞后。直接用docker.io包虽然也能跑但在涉及新功能或安全补丁时官方仓库体验更好。2.3 CentOS上安装Docker的注意点CentOS 7虽然以前是运维主流但已经停止维护新项目不建议使用。如果仍在维护存量CentOS 7机器安装流程大致是sudo yum install -y yum-utils sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo sudo yum install -y docker-ce docker-ce-cli containerd.io sudo systemctl enable --now dockerCentOS 7默认内核是3.10运行Docker可以但运行K8S时容易遇到网络和模块问题。更推荐的方式是迁移到Rocky Linux或AlmaLinux 9它们和CentOS使用习惯接近内核更新生命周期也更长。2.4 配置镜像加速解决拉取慢的问题docker pull默认从Docker Hub拉取镜像。国内网络环境下官方仓库可能很慢或经常超时。解决思路是配置镜像加速器也就是registry-mirrors。配置文件位于/etc/docker/daemon.json如果文件不存在则新建{ registry-mirrors: [ https://你的阿里云镜像加速地址 ] }阿里云容器镜像服务会为每个账号分配独立的加速地址在中科大开源镜像站等页面也能找到公共加速地址。使用时以对应服务商的当前说明为准因为地址可能会调整。修改后必须重启Dockersudo systemctl daemon-reload sudo systemctl restart docker验证是否生效docker info | grep -A 3 Registry Mirrors配置完成后docker pull mysql:8.0这类操作通常会明显变快。需要注意的是镜像加速只影响拉取不影响构建、上传和Docker Hub页面访问。2.5 安装完成后的验证步骤与常见启动报错安装完成后不要急着直接跑业务镜像先做一次最小验证docker version docker run --rm hello-worldhello-world是一个极小的测试镜像只要能正常拉取并输出提示信息说明Docker安装、镜像分发、容器运行链路都正常。接着再验证服务管理systemctl enable docker systemctl start docker systemctl status docker常见问题有三个。第一个是docker: permission denied。原因是普通用户不在docker组而/var/run/docker.sock权限受限。学习环境可以执行sudo usermod -aG docker $USER并将用户加入docker组后重新登录生产环境要慎重因为docker组内的用户权限基本等同于root。第二个是docker进程没有启动。执行docker info报Cannot connect to the Docker daemon时先看systemctl status docker再通过journalctl -u docker查看启动日志。第三个是daemon.json写错导致Docker启动失败。比如JSON格式多了一个逗号或镜像加速地址格式错误。可以使用dockerd --config-file /etc/docker/daemon.json校验配置错误时能看到具体行号。2.6 使用Windows本机学习时Docker Desktop启动失败的排查很多初学者本机是Windows会安装Docker Desktop。Docker Desktop在Windows上依赖WSL2或Hyper-V启动失败最常见的原因不是软件问题而是虚拟化功能没有开启。常见报错包括Docker Desktop failed to start because virtualisation support wasnt detectedWeve detected that you have an incompatible version of Windows排查顺序可以这样走打开任务管理器在“性能”页确认CPU的虚拟化状态是否显示“已启用”。在“控制面板 - 程序 - 启用或关闭Windows功能”中确认“适用于Linux的Windows子系统”和“虚拟机监控程序平台”已勾选。在管理员PowerShell中执行wsl --status确认WSL2已安装且默认版本正确。如果虚拟化在BIOS中被关闭需要重启进入BIOS开启Intel VT-x或AMD-V。检查Windows版本是否满足Docker Desktop当前版本要求版本过旧时升级系统补丁。问题现象可能原因检查方式处理方向启动提示未检测到虚拟化支持BIOS关闭虚拟化或Windows虚拟化功能未开启任务管理器性能页、BIOS设置开启VT-x/AMD-V并重启提示Windows版本不兼容系统版本过旧或WSL2未安装winver、wsl --status更新系统、安装WSL2启动后一直停留在startingWSL2环境异常wsl --shutdown重启WSL或重置Docker Desktop需要明确一点Docker Desktop只适合本机开发调试。真正面向服务器侧的实践仍然建议准备一台Linux虚拟机或云主机这样更接近生产运维环境。3. Docker常用命令与两个中间件实战熟悉Docker不能靠背命令表要靠反复跑任务。下面从命令速查开始然后用MySQL 8.0和Redis主从两个实战场景把镜像、容器、网络、数据卷、Compose串起来。3.1 镜像和容器的核心命令速查镜像和容器是Docker最核心的两个对象。镜像可以理解为“运行模板”容器是“模板运行后的实例”。常用命令如下操作命令拉取镜像docker pull nginx:1.27查看本地镜像docker images删除镜像docker rmi nginx:1.27启动容器docker run -d --name web -p 8080:80 nginx:1.27查看运行容器docker ps查看所有容器docker ps -a停止容器docker stop web启动已有容器docker start web删除容器docker rm web查看日志docker logs -f web进入容器docker exec -it web bash查看容器详情docker inspect web几个容易混淆的地方docker start和docker run不同。run是创建并启动新容器start是启动一个已经存在的容器。docker ps -a能看到已退出容器排查问题时一定要加-a。删除容器前如果容器还在运行需要先docker stop或者使用docker rm -f强制删除。3.2 docker exec进入容器后能查什么、不能查什么进入容器调试是运维高频操作。标准用法是docker exec -it mysql8 bash如果镜像基于Alpine或精简系统可能没有bash可以改用shdocker exec -it mysql8 sh进入容器后可以查看进程、网络、配置文件和运行日志。例如ps aux ss -lntp cat /etc/nginx/nginx.conf但这里有一个关键认知容器里的修改不会保留在镜像里容器一旦被删除重建所有手动改动都会丢失。生产环境遇到配置问题正确方式是把改动写进配置文件、重新构建镜像或使用挂载文件而不是直接进容器手改。另一个常见错误是docker exec -it 容器名 bash返回exec: bash: executable file not found。这不是命令没写对而是镜像里根本没有bash。先确认容器运行状态再尝试sh即可。3.3 数据卷和端口映射让容器数据不丢、服务可访问容器是临时的但业务数据需要持久化。Docker解决数据持久化主要有两种方式命名卷和目录挂载。命名卷由Docker管理适合保存数据库数据目录挂载直接把宿主机目录映射进容器适合挂载配置文件、代码和日志。两种方式都通过-v参数完成# 命名卷删除容器后数据仍保留 docker run -d --name mysql-data -v mysql_data:/var/lib/mysql mysql:8.0 # 目录挂载把宿主机配置映射进容器 docker run -d --name nginx-config -v /opt/nginx/conf:/etc/nginx/conf.d:ro nginx:1.27端口映射使用-p参数格式是“宿主机端口:容器端口”docker run -d --name web -p 8080:80 nginx:1.27这里的8080是宿主机对外端口80是容器内Nginx监听端口。如果宿主机8080端口被占用启动会报bind: address already in use使用ss -lntp | grep 8080查看占用进程。3.4 实战一用Docker安装MySQL 8.0并完成建库和连接下面以一个运维常见任务为例在Docker中安装MySQL 8.0配置UTF-8字符集完成建库并从另一个容器连接。先创建网络方便后续容器之间用容器名通信docker network create ops-demo创建目录并准备MySQL配置文件mkdir -p /opt/mysql/conf /opt/mysql/data cat /opt/mysql/conf/my.cnf EOF [mysqld] character-set-serverutf8mb4 collation-serverutf8mb4_unicode_ci EOF启动MySQL容器docker run -d \ --name mysql8 \ --network ops-demo \ -p 3306:3306 \ -v /opt/mysql/conf/my.cnf:/etc/mysql/conf.d/my.cnf:ro \ -v /opt/mysql/data:/var/lib/mysql \ -e MYSQL_ROOT_PASSWORDroot123 \ -e TZAsia/Shanghai \ mysql:8.0参数含义如下--name mysql8容器名也是同网络内其他容器访问它的主机名。--network ops-demo加入自定义网络容器之间可以用名称通信。-p 3306:3306对外暴露MySQL端口。-v分别挂载配置和数据目录配置文件是只读挂载。-e MYSQL_ROOT_PASSWORDroot123初始化root密码。-e TZAsia/Shanghai设置时区。验证是否启动成功docker logs mysql8 | tail -20 docker exec -it mysql8 mysql -uroot -proot123 -e select version();如果看到版本号说明MySQL已正常运行。接着建库docker exec -it mysql8 mysql -uroot -proot123 -e create database ops_demo default character set utf8mb4;再从另一个临时容器连接测试docker run --rm --network ops-demo mysql:8.0 mysql -hmysql8 -uroot -proot123 -e show databases;这里用了一个小技巧--rm表示容器执行完命令后自动清理-h mysql8表示使用容器名访问MySQL服务。生产环境使用MySQL时有几个点必须注意不要用root123这类弱密码不要把3306端口直接暴露到公网建议通过网络策略限制访问来源并针对数据目录做定期备份。MySQL 8.0默认认证插件是caching_sha2_password老版本客户端连接时可能出现认证失败需要认准版本兼容性。3.5 实战二用Docker Compose搭建Redis主从单个容器适合理解基础命令但实际运维中一个应用往往依赖多个服务。Docker Compose用于定义和运行多容器应用配置文件是docker-compose.yml。下面搭建一个Redis主从环境一个主节点、一个从节点。主节点开启AOF持久化从节点通过--replicaof连接到主节点。services: redis-master: image: redis:7.2 container_name: redis-master command: [redis-server, --appendonly, yes] ports: - 6379:6379 volumes: - redis-master-data:/data redis-slave: image: redis:7.2 container_name: redis-slave command: [redis-server, --replicaof, redis-master, 6379, --appendonly, yes] depends_on: - redis-master ports: - 6380:6379 volumes: - redis-slave-data:/data volumes: redis-master-data: redis-slave-data:在保存文件的目录执行docker compose up -d查看容器状态docker compose ps验证主从关系docker exec -it redis-slave redis-cli info replication输出中如果看到role:slave并且master_link_status:up说明从节点已成功连接主节点。这里的要点是depends_on只控制容器启动顺序不保证主节点在从节点启动时已经完成初始化。生产级Compose配置应该添加健康检查例如通过healthcheck判断Redis是否真正可连接后再启动从节点。另外要注意Redis主从复制不等于高可用。主节点宕机后从节点不会自动成为主节点。实现自动故障切换需要Redis Sentinel或Redis Cluster这是后面扩展的方向。3.6 这阶段最容易遇到的三个“坑”第一容器启动后立即退出。常见原因是启动命令没有保持前台运行。比如Dockerfile中写service nginx start命令执行完进程退出容器也就退出了。正确方式是运行前台命令Nginx应使用nginx -g daemon off;或者直接把启动逻辑交给镜像自己的ENTRYPOINT。第二反复出现port is already allocated。这通常是宿主机端口已被占用。不要盲目换端口先查清占用来源否则可能造成端口冲突扩大。第三数据丢失。很多人使用docker run启动数据库时没加-v容器删除后数据全部丢失。数据库类容器必须提前规划数据卷或目录挂载并在删除容器前确认备份。4. 进入K8S前先把这几个概念理解透K8S的难点不是命令多而是引入了一整套抽象概念。如果不理解Pod、控制器、控制面这些基础直接看YAML会像看天书。4.1 Pod是K8S的最小调度单元而不是直接调度容器在Docker时代最小运行单位是容器。在K8S里最小调度单位变成了Pod。一个Pod可以包含一个或多个容器。Pod里的容器共享同一个网络命名空间、共享存储卷可以通过localhost互相访问。为什么会这样设计因为有些场景下多个容器必须部署在同一台机器上、共享生命周期典型场景是业务容器和日志采集sidecar容器。看一个最小Pod定义apiVersion: v1 kind: Pod metadata: name: nginx-pod spec: containers: - name: nginx image: nginx:1.27 ports: - containerPort: 80简单理解Pod是一个“逻辑主机”容器是这个主机上的进程。用户通常不直接创建Pod而是通过Deployment等控制器创建由控制器保证Pod数量符合期望值。容易误解的是一个Pod内有多个容器不等于“多个容器随便放”。它们必须共享网络命名空间端口不能冲突并且K8S调度、重启都以Pod为单位不会单独重启某一个容器。4.2 Entrypoint和CMD到底指什么K8S如何覆盖容器核心是一个启动命令。镜像里由Dockerfile的ENTRYPOINT和CMD定义两者有明确分工ENTRYPOINT是主命令通常固定不变。CMD是默认参数或默认命令可以被覆盖。例如镜像内部逻辑相当于ENTRYPOINT [nginx] CMD [-g, daemon off;]启动容器时docker run nginx -g daemon off;会把后面的参数追加给ENTRYPOINT替换CMD。在K8S的Pod定义中字段command对应Dockerfile的ENTRYPOINT字段args对应Dockerfile的CMD。一个常见写法是containers: - name: busybox image: busybox:1.36 command: [/bin/sh] args: [-c, echo hello; sleep 3600]这个写法覆盖了镜像默认启动命令让容器执行一段脚本。在实际排障时Pod一直CrashLoopBackOff很大概率就是启动命令写错、路径不存在或进程启动后立刻退出。容器进程必须是前台进程。如果启动命令是后台启动服务比如在shell脚本里执行service nginx start然后脚本结束容器就会退出。这个错误在初学K8S时非常常见。4.3 控制面和工作节点K8S集群骨架K8S集群分成控制面和工作节点两部分。控制面是大脑工作节点是执行者。组件所在节点主要职责kube-apiserver控制面所有请求的唯一入口负责认证、鉴权和状态变更etcd控制面存储集群所有状态数据kube-controller-manager控制面运行各种控制器维持期望状态kube-scheduler控制面决定Pod调度到哪个工作节点kubelet工作节点负责Pod生命周期和容器运行时交互kube-proxy工作节点负责Service的网络转发规则containerd工作节点实际运行容器的运行时学习时可以通过kubectl get nodes查看节点状态通过kubectl get pods -A查看所有命名空间的Pod。如果kubectl get nodes显示NotReady通常问题出在容器运行时、网络插件或节点资源上而不是Pod配置本身。4.4 从单机Docker到集群K8S运维视角的变化单机Docker时代运维关心的是这个容器在本台机器上是否运行、日志是否正常、端口是否可访问。到了K8S阶段关心的问题变成了期望副本是多少、当前副本是多少、Pod卡在哪个状态、Service是否选中了正确的Pod、节点资源是否充足。K8S的核心设计是声明式。运维通过YAML描述“想要的状态”控制器负责把“实际状态”拉向“期望状态”。比如配置replicas: 3某个Pod挂了控制器会立刻创建新的Pod补齐数量。这种能力在Docker单机模式下需要额外脚本或外部编排实现。5. K8S集群搭建、常用命令和只读权限实践在理解核心概念后再上手搭建集群会顺手很多。这一阶段不是要把生产级集群一步到位而是先把控制面、工作节点、Pod调度、权限控制跑通。5.1 学习环境和生产环境的集群搭建思路学习K8S不一定要用kubeadm从头搭三节点集群。更合理的方式是按阶段选择工具环境推荐工具适用目标第一次接触minikube 或 kind单机体验Pod、Deployment、Service学习多节点k3s 或 kubeadm理解控制面和工作节点协同生产级kubeadm、二进制