1. 用Docker装软件,到底解决了什么问题
先说个我自己的经历。前几年在一台服务器上装Redis,系统是CentOS 7,默认源里只有Redis 3.2,但项目要用Redis 6的Stream类型,只能自己编译。编译倒是不难,难的是编译完发现系统里还装着一个PHP扩展,它依赖老版本的libevent,我一升级Redis,PHP那边直接崩了。折腾了一下午,最后老老实实把系统重装了一遍。
这个场景你应该不陌生。传统方式安装软件的痛点,总结起来就是三个:依赖冲突、环境残留、升级困难。你在系统里装的每个软件,都在往/usr/lib、/etc、/var下面塞东西,软件多了以后,谁也说不清哪个文件是谁的,哪个库被谁覆盖了。
Docker解决这个问题的方式很直接:把软件连同它专属的操作系统环境,一起打包成一个镜像。镜像就是一个只读模板,里面已经装好了运行这个软件所需要的所有依赖、配置、动态链接库,甚至包括特定的Linux发行版基础环境。当你运行这个镜像时,Docker基于镜像创建一个独立的容器,容器里的进程只能看到镜像里给它准备好的那一套环境,跟宿主机其他的软件互不干扰。
打个比方。传统安装像你往一个合租房里搬家具,床、衣柜、书桌都摆在公共区域,你搬进来一套沙发,可能就得把别人的电视柜挪走。Docker则是每个软件住一间独立的精装公寓,家具、电器、水管电线全部标配,你想换房(升级版本),直接换一套公寓住进去就行,旧公寓整间退掉,干干净净。
很多人问,那我直接用虚拟机不也一样吗?虚拟机是虚拟出一整台计算机,里面装完整操作系统,开销大、启动慢、资源占用高。容器则共享宿主机内核,只隔离用户空间的进程、文件系统、网络和权限,启动一个容器往往只要几百毫秒,内存占用可能只有几十兆。正因为这个特性,Docker特别适合用来装那些本身没有界面、以服务方式运行的后端软件:数据库、缓存、消息队列、Web服务器、定时任务平台,等等。
不过也要说句公道话,Docker不是万能的。以下几种情况,我仍然建议你老老实实在宿主机装:
- 需要直通GPU做深度学习训练的(虽然有nvidia-container-toolkit,但配置成本不低);
- 对IO性能要求极其苛刻的数据库场景(容器有存储驱动层的开销,虽然现代驱动已经非常接近裸盘,但极端场景还是有差距);
- 需要长期跑桌面GUI应用的(不是不能跑,但显示方案绕来绕去,体验一般)。
除此之外,用Docker安装部署软件的收益是非常明显的。这篇就围绕我自己折腾Docker装软件的经验,从环境准备、单容器实战、编排实战、依赖管理到开发者集成、特殊架构适配,完整梳理一遍。
2. 环境准备:Windows、macOS、Linux下的Docker安装与镜像加速配置
2.1 不同系统的正确安装姿势
Docker本身是Linux上的原生技术,它依赖Linux内核的namespace(命名空间)和cgroups(控制组)这两个核心机制来实现隔离和资源限制。你在Windows或macOS上装Docker,本质上是装一个轻量级Linux虚拟机,然后在虚拟机里跑Docker引擎。Docker Desktop帮你把这一层封装好了,所以你几乎感觉不到虚拟机的存在。
不同系统下的安装选型,我直接给结论:
| 操作系统 | 推荐方案 | 说明 |
|---|---|---|
| Windows 10/11(64位,支持WSL2) | Docker Desktop for Windows | 用WSL2作为后端,性能和体验都最好 |
| Windows Server | docker-ce + containerd(原生Windows容器或Linux容器均可) | 生产环境常用 |
| macOS(Intel/Apple Silicon) | Docker Desktop for Mac | Apple Silicon上自动用VirtioFS加速文件共享 |
| Ubuntu/Debian | 官方apt源安装docker-ce | 不要装老旧系统源里的docker.io |
| CentOS/RHEL/Rocky | yum/dnf安装docker-ce | 需要先配置官方或镜像源 |
| 龙芯/飞腾等国产平台 | 系统厂商维护的docker-engine包,或源码编译 | 见第7章详细讲 |
Windows下安装Docker Desktop,我需要强调一个前置条件:必须先启用WSL2。很多人装完Docker Desktop提示启动失败,十有八九是没装Linux内核更新包,或者没有在"控制面板→启用或关闭Windows功能"里勾选"适用于Linux的Windows子系统"和"虚拟机平台"两个选项。装完这两个组件后重启,再在管理员PowerShell里执行wsl --set-default-version 2,最后再装Docker Desktop,一路Next就不会有问题。
Linux下用官方脚本安装是最省事的:
curl -fsSL https://get.docker.com -o get-docker.sh sudo sh get-docker.sh这个脚本会自动检测你的发行版,配置官方仓库,然后安装docker-ce、docker-ce-cli、containerd.io、docker-compose-plugin这些组件。不想用官方脚本的话,Ubuntu可以手动添加Docker的apt源,CentOS则添加yum源,网上文档很多,但核心就两步:导入GPG密钥 + 写入repo文件。
2.2 安装完之后必做的三件事
不管哪个系统,装完Docker先别急着拉镜像,做下面三件事:
第一,把当前用户加入docker组(仅限Linux/macOS)。默认情况下只有root和docker组的用户能操作Docker守护进程,不然每条命令都要加sudo,麻烦且容易出权限问题:
sudo usermod -aG docker $USER newgrp docker注意:把用户加入docker组相当于授予该用户root级别的宿主机权限,因为docker组可以挂载宿主机目录、执行特权容器。个人开发机没问题,生产环境服务器要谨慎。
第二,配置镜像加速器。Docker Hub部署在国外,直接拉镜像经常几KB/s甚至超时。国内各大云厂商都提供registry mirror服务,它本质上是一个Docker镜像的代理缓存,你把Docker守护进程的registry-mirrors指向它,拉镜像时优先从国内节点下载。
在Docker Desktop里,打开Settings → Docker Engine,编辑JSON:
{ "registry-mirrors": [ "https://docker.m.daocloud.io", "https://dockerproxy.com" ] }Linux环境下则编辑/etc/docker/daemon.json,然后sudo systemctl restart docker。
补充:加速器地址不是我随便写的,云厂商的加速器地址通常是
https://xxxx.mirror.aliyuncs.com这种,每个人账号对应的地址不同,需要登录容器镜像服务控制台获取。上面给的公共加速器我实测过,但仍然建议你优先用自己的——公共节点负载高,宕机是常事。另外,别把加速器地址当成什么见不得光的东西,它就是一个常规的镜像源配置。
第三,验证Docker是否正常工作:
docker run --rm hello-world这个测试镜像只有几KB,运行后会打印一段Docker工作正常的说明然后退出。如果这一步能顺利跑通,说明引擎、网络、镜像拉取链路都没问题。
2.3 为什么加速器配置要放在环境准备阶段
我在帮别人排查Docker问题的时候发现,80%的"拉镜像失败"都和网络有关,但很多人第一反应是去改容器配置、换镜像tag,结果白折腾。拉镜像是最容易被网络影响的环节,而配置加速器是最低成本、最立竿见影的优化手段。
关于镜像加速的原理,我再多说一句。当你执行docker pull redis:7.2时,Docker守护进程并不是直接从Docker Hub下载blob,而是先去Hub查索引,然后根据索引信息去Registry拉取层数据。配置registry-mirrors后,Docker会优先从mirror地址拉取——mirror本身会和源站同步数据,你在国内拉取时,走的其实是国内节点。这样一来,原本可能需要几分钟甚至超时的下载,通常能缩短到十几秒。
3. 首个容器实战:以Redis为例跑通"拉取-运行-验证"
3.1 直接run还是先pull?先用好tag制度
很多教程上来就让你docker run redis,实际Docker会先自动帮你拉取镜像再运行,所以很少有人单独执行docker pull。但我建议新手还是先手动pull一次,原因很简单:你要清楚自己拉的是什么版本。
Redis镜像在Docker Hub上的tag规则非常明确:
redis:latest:最新稳定版,不推荐生产环境使用,因为不可控;redis:7.2:7.2系列的最新补丁版本,推荐日常使用;redis:7.2-alpine:基于Alpine Linux的精简版,体积只有几十MB;redis:7.2-bookworm:基于Debian Bookworm的标准版,功能最全;redis:7.0.14:精确到小版本号,锁定不变。
我的习惯是,本地测试用alpine系列,体积小、启动快;生产环境用bookworm或官方默认的Debian系列,因为Alpine用的是musl libc,个别原生模块可能编译不兼容。
docker pull redis:7.2-alpine3.2 带持久化和密码的运行参数详解
拉完镜像,执行下面这条命令,这是Docker装软件最核心的一条命令:
docker run -d \ --name redis-test \ -p 6379:6379 \ -v redis-data:/data \ -e TZ=Asia/Shanghai \ redis:7.2-alpine \ redis-server --appendonly yes --requirepass MyPassw0rd逐个解释参数,这些都是你后面装任何软件都要用到的:
-d:后台运行(detach模式),不加这个参数容器会占用终端,日志直接刷屏;--name redis-test:给容器起名字,后续docker start/stop/logs/exec都用这个名字操作;-p 6379:6379:端口映射,宿主机6379端口转发到容器内6379端口。容器内是一个隔离的网络空间,不映射的话,宿主机上的程序访问不到它;-v redis-data:/data:数据卷挂载,冒号前是宿主机上的卷名或绝对路径,冒号后是容器内的目录。Redis的AOF持久化文件默认存在/data,如果不挂载卷,容器一旦删除,所有数据全部消失;-e TZ=Asia/Shanghai:设置容器内时区。容器默认是UTC时区,比北京时间慢8小时,跑定时任务时会踩坑;redis-server --appendonly yes --requirepass MyPassw0rd:这后面的参数是传给容器内Redis主进程的命令行参数。镜像默认的启动命令就是redis-server,你可以追加参数覆盖默认配置。
关于-v,我要多说一句。这里我用了卷名redis-data,而不是/home/user/data这种绝对路径。两者的区别是:具名卷由Docker管理,存储在/var/lib/docker/volumes/下,迁移、备份用docker volume命令很方便;绑定挂载(bind mount)则直接把宿主机目录映射进容器,你可以在宿主机上直接看到和修改文件。数据库类应用,我建议用具名卷,省心、权限问题少;需要直接在宿主机上改配置文件、看日志的,用绑定挂载更直观。
3.3 验证容器是否真的在干活
运行起来之后,新手最容易犯的错就是"以为容器跑起来了,其实它早就退出了"。验证方法是一套组合拳:
# 查看容器状态,STATUS显示Up表示正常运行,Exited说明已退出 docker ps -a # 查看日志,这是排障第一入口 docker logs redis-test # 进入容器内部执行命令 docker exec -it redis-test sh # 在容器内用redis-cli验证 redis-cli -a MyPassw0rd ping # 应该输出:PONG如果docker ps -a显示容器Exited,不要慌,用docker logs redis-test看退出原因。最常见的几种情况:
- 端口被占用:报错
bind: address already in use,换宿主机的映射端口即可; - 配置文件参数写错:Redis会打印
Bad directive or wrong number of arguments; - 权限不足:挂载的数据卷目录属主不对,容器内redis用户写不进去。
还有一个排查利器是docker inspect:
docker inspect redis-test它会输出容器完整的配置信息,包括挂载的卷、环境变量、网络配置、退出码、重启策略等。JSON很长,可以配合grep或jq过滤关键字段:
docker inspect redis-test | grep -A 5 Mounts docker inspect redis-test | jq '.[0].State'到这里,你已经完成了用Docker安装并运行第一个软件的完整流程。这条路径——拉镜像、起容器、配参数、验证状态——是所有Docker装软件场景的共同母题。
4. 进阶编排:用Docker Compose搭建Redis主从复制集群
4.1 为什么单容器不够用了
单个Redis容器解决的是"有一个Redis能用"的问题。但实际开发中,你可能需要一主一从做读写分离,或者一主两从加哨兵做高可用。这时候用docker run一条条命令敲也不是不行,但有两个问题:
- 容器之间要联网通信,你得先自己创建自定义网络,再在启动时指定
--network,步骤繁琐; - 整套环境的配置散落在历史命令里,换一台机器部署,全部重来。
Docker Compose就是为了解决"多容器环境编排"而存在的。它用一个YAML文件描述整套服务的配置,docker compose up -d一条命令全部拉起,docker compose down一键全部销毁。
4.2 先搞懂主从复制的原理,再写配置
Redis主从复制的基本逻辑:从节点启动后,向主节点发送SYNC命令(新版本是PSYNC),主节点生成RDB快照发送给从节点,之后主节点把每一次写操作以命令流的方式持续转发给从节点。所以从节点能实时同步主节点的数据。
在原生Redis里,配置从节点只需要在redis.conf加一行:
replicaof <master-ip> <master-port>Docker环境下,主节点容器的IP不是固定的(除非指定固定IP),所以更优雅的做法是利用Docker内置的DNS解析——在同一个自定义网络里,容器可以通过服务名直接访问对方。这就是Compose文件天然适合做多容器架构的原因。
4.3 docker-compose.yml完整配置
下面是一份我实测过的docker-compose.yml,实现一主一从带密码验证:
services: redis-master: image: redis:7.2-alpine container_name: redis-master restart: unless-stopped ports: - "6379:6379" volumes: - redis-master-data:/data environment: - TZ=Asia/Shanghai command: redis-server --appendonly yes --requirepass MasterPass --masterauth MasterPass redis-slave: image: redis:7.2-alpine container_name: redis-slave restart: unless-stopped ports: - "6380:6379" volumes: - redis-slave-data:/data environment: - TZ=Asia/Shanghai depends_on: - redis-master command: redis-server --appendonly yes --requirepass SlavePass --replicaof redis-master 6379 --masterauth MasterPass volumes: redis-master-data: redis-slave-data:这个配置里几个关键点:
--replicaof redis-master 6379:从节点通过服务名redis-master找到主节点,Docker内置DNS会解析到主节点容器的IP;--requirepass和--masterauth:主节点要求客户端认证,所以从节点同步时也必须提供密码,两个参数要配套设置,否则从节点会一直报NOAUTH Authentication required;depends_on:声明启动顺序,从节点等主节点先启动。但实际上Redis的replicaof机制有自动重连,即使主节点晚启动,从节点也会持续重试,所以这个字段更像是一种友好声明;restart: unless-stopped:容器异常退出或宿主机重启时自动拉起,生产环境必备。
启动方式:
docker compose up -d4.4 验证主从同步是否正常
全部启动后,分别验证两个容器状态:
docker ps # 确认两个容器都是Up状态 # 登录从节点查看复制状态 docker exec -it redis-slave redis-cli -a SlavePass info replication输出里关注几个字段:
role:slave,确认当前节点角色是从节点;master_host:redis-master,确认主节点地址解析正确;master_link_status:up,这是最关键的,只有up才表示主从连通;master_last_io_seconds_ago,距离上次和主节点通信的时间,数字过大说明同步不健康。
然后再验证数据同步:
# 在主节点写入数据 docker exec -it redis-master redis-cli -a MasterPass set name "docker" # 在从节点读取 docker exec -it redis-slave redis-cli -a SlavePass get name # 输出 "docker" 说明同步正常我踩过的一个坑值得提醒:如果主节点设置了requirepass,而从节点没有正确设置masterauth,从节点的日志会每隔几秒打一条错误:
MASTER <-> REPLICA sync: Master replied to PING, replication can continue...主节点返回了PING,但因为没带认证信息,后续的同步请求会被拒绝。此时用docker logs redis-slave能非常清晰地看到NOAUTH字样,马上就能定位问题。
5. 基础软件的进阶玩法:青龙面板的容器依赖管理
5.1 为什么容器化部署对这类应用特别友好
青龙面板是一个定时任务管理平台,在Docker环境下非常流行。这类平台本身就是多语言脚本的执行环境,涉及Node.js、Python、JavaScript等运行时的各种依赖库。如果用传统方式部署,你得在服务器上手动装Node.js、Python、pip、npm,还要处理版本冲突;而用Docker,镜像里已经把运行时环境全部备好了:
docker run -d \ --name qinglong \ -p 5700:5700 \ -v ql-data:/ql/data \ -e TZ=Asia/Shanghai \ whyour/qinglong:latest启动后访问http://宿主机IP:5700就能进入Web界面。一个定时任务平台,从下载到运行只需要几分钟,这就是容器化的价值。但这里真正值得展开讲的,不是启动,而是依赖管理——这是我在使用过程中踩坑最多的地方。
5.2 容器内依赖管理:三个常见误区
误区一:直接在容器里手动安装依赖,然后以为一劳永逸。你会看到很多教程让你执行:
docker exec -it qinglong bash npm install -g xxx pip install xxx这在当下是生效的,但容器一旦重建(升级镜像、服务器迁移、异常回滚),所有手动安装的依赖全部消失。因为容器本身是临时的,数据卷持久化的只是/ql/data目录,而npm的全局包安装在容器文件系统里,不属于持久化数据。
误区二:所有依赖都装到全局。有些依赖只在某个特定脚本里用到,装成全局包反而容易版本冲突。比如一个脚本要求requests==2.28.1,另一个脚本要求requests==2.31.0,全局只能装一个。
误区三:忽视依赖的时区设置导致的定时任务偏差。青龙镜像虽然可以通过-e TZ=Asia/Shanghai设置时区,但如果你管理的任务脚本内部使用了datetime.now(),它读取的是脚本运行时环境的时区,不是数据库里的时区。这个问题在容器里表现得尤为隐蔽,因为容器基础镜像默认UTC,如果你忘了设置环境变量,定时任务会准时提前8小时执行。
5.3 我推荐的依赖管理方案:自定义镜像 + 启动初始化脚本
依赖管理最稳妥的思路是:把依赖固化到镜像里,而不是临时装进容器里。具体做法是写一个自己的Dockerfile:
FROM whyour/qinglong:latest # 设置时区 ENV TZ=Asia/Shanghai # 安装系统级依赖 RUN apk add --no-cache tzdata bash curl # 安装Python依赖 RUN pip3 install --no-cache-dir requests apscheduler pycryptodome # 安装Node依赖 RUN npm install -g pnpm ts-node typescript # 声明数据卷(沿用官方镜像配置) VOLUME /ql/data然后构建并运行:
docker build -t qinglong-custom:v1 . docker run -d --name qinglong -p 5700:5700 -v ql-data:/ql/data -e TZ=Asia/Shanghai qinglong-custom:v1这样每次重建容器,镜像里已经包含了声明的依赖,不会再丢失。不足是这个方案有个学习成本:你需要了解Dockerfile的编写,并且更新镜像时要重新构建。
如果不想用Dockerfile,日常维护也可以把pip和npm的依赖清单存到数据卷里:
# 在宿主机上建目录,挂载为容器的初始化目录 docker run -d \ -v $(pwd)/qinglong-init:/ql/init \ ...然后在Web界面里,把依赖管理配置成从文件读取。具体来说,青龙面板的依赖管理支持你保存一份依赖清单,在依赖缺失时会触发安装。
5.4 容器重建后快速恢复依赖的实操清单
我自己的服务器上跑着青龙容器,一次升级镜像把所有依赖搞丢之后,我给自己的恢复流程定了个规矩:
- 升级前先导出清单:
docker exec -it qinglong pip3 freeze > requirements.txt,Node端用npm list -g --depth=0导出; - 升级后不急着配脚本,先让容器跑起来,然后通过Web界面的依赖管理,把上一步导出的清单重新安装;
- 装完必须做冒烟验证:随便挑一个依赖库执行
python3 -c "import requests; print(requests.__version__)",确认核心依赖锁定了版本。
这套流程经历过两次实际验证,比之前"手动一个个装回去"节省了大量时间。
6. 开发提效:IDEA一键打包Docker镜像
6.1 为什么建议直接在IDEA里完成镜像打包
Docker不只是运维用来装软件的工具,对开发者来说,它也是应用交付的重要载体。过去把Spring Boot应用打成镜像,流程是:本地mvn package打出jar包 → 写Dockerfile → scp到服务器 → ssh登录服务器 → docker build → docker run。链路过长,每步都有可能出错。
IDEA自带的Docker插件把最后几步集成进了IDE。你在配置里指定Dockerfile路径和构建参数,点击执行,IDEA自动帮你完成构建、推送、甚至部署到远程服务器。对于频繁迭代开发环境的场景,效率提升非常明显。
6.2 从零配置:连接Docker与Run Configuration
第一步,让IDEA能连上Docker守护进程。如果Docker和IDEA在同一台机器上,Settings → Build, Execution, Deployment → Docker,点击加号,选择Docker Desktop(Windows/macOS)或Unix socket(Linux),Test Connection显示成功即可。
如果是远程服务器上的Docker,需要在服务器上开启远程API访问。这一步有安全风险,因为默认情况下Docker API没有认证,任何人都能连上你的守护进程并执行任意命令。我建议至少配置TLS证书,或者用SSH隧道方式连接:
ssh -L 2375:/var/run/docker.sock user@server然后在IDEA里用tcp://localhost:2375连接,走SSH隧道转发,比裸奔暴露2375端口安全得多。
第二步,写好Dockerfile。以常见的Spring Boot应用为例:
# 多阶段构建 FROM maven:3.9-eclipse-temurin-17 AS builder WORKDIR /app COPY . . RUN mvn clean package -DskipTests # 运行阶段 FROM eclipse-temurin:17-jre WORKDIR /app COPY --from=builder /app/target/*.jar app.jar EXPOSE 8080 ENTRYPOINT ["java", "-jar", "app.jar"]多阶段构建的核心价值是把"构建环境"和"运行环境"分开。构建阶段用maven镜像,里面有完整的JDK和Maven,体积几个GB;运行阶段只拷贝最终产出的jar包,基于精简的JRE镜像,最终镜像可能只有200MB。
第三步,配置Run Configuration。在IDEA右上角选择 Edit Configurations,新增Dockerfile运行配置,指定Dockerfile路径,镜像tag建议写成${project.name}:v1。点击运行,IDEA的底部会实时输出构建日志,构建完成后自动注册到本地镜像库。
6.3 打包过程中最常见的坑
镜像体积过大。如果不做多阶段构建,而是用FROM maven:3.9直接在上面打包运行,镜像体积会膨胀到几个GB。多阶段构建是必须的,不是可选优化项。
时区问题。容器默认UTC时区,Java应用打印的日志时间会比北京时间慢8小时。打包时在Dockerfile里加上:
ENV TZ=Asia/Shanghai RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone第二句可能因基础镜像缺少tzdata包而报错,所以有时要先apt-get install -y tzdata或apk add tzdata。
.dockerignore没写。没有.dockerignore的话,构建上下文会把整个项目目录(包括target/、.git/、logs/)都发给Docker守护进程,构建速度慢到怀疑人生。在项目根目录放一个:
target/ .git/ .idea/ *.iml logs/依赖缓存失效。Maven构建最耗时的部分是下载依赖,每次构建都重新下意味着白白浪费时间。优化做法是利用Docker层缓存机制,把依赖下载单独放一层:
COPY pom.xml . RUN mvn dependency:go-offline COPY src ./src RUN mvn package只要pom.xml没变,这一层就可以直接复用缓存,后续构建时间从几分钟降到几秒。
7. 国产化适配:龙芯机器上跑Docker的实践经验
7.1 龙芯平台的特殊性
龙芯处理器采用的是自主指令集LoongArch,不是大家更熟悉的x86(Intel/AMD)也不是ARM。这意味着市面上绝大多数现成的Docker镜像——不管官方还是第三方——都没有针对龙芯编译过的版本。你执行docker pull mysql:8.0,大概率会得到一句no matching manifest for linux/loong64 in the manifest list entries。
这不是Docker本身的问题,而是镜像的提交者没有构建LoongArch架构的版本。理解这一点,是搞定龙芯Docker的第一步。
7.2 在龙芯上安装Docker引擎
龙芯的新版本统信UOS、麒麟等操作系统,通常已经在源里带了docker-engine或docker-ce包,优先用系统源安装,因为官方已经做了适配:
# 以统信UOS/麒麟为例 sudo apt update sudo apt install docker.io sudo systemctl enable --now docker或者使用龙芯开源社区维护的安装包,覆盖面更广。
安装完验证一下架构:
docker info | grep Architecture # 输出应为 loong64 或 loongarch64注意这里有个容易混淆的点:LoongArch的Docker架构标识是loong64还是loongarch64,取决于Docker版本的规范写法。较新版本用的是loong64,与Go语言对龙芯架构的命名保持一致。
7.3 没有现成镜像的三种应对策略
既然Docker Hub上几乎没有LoongArch的镜像,我们实际用的时候有三个办法:
办法一:寻找龙芯适配过的镜像源。龙芯团队维护了一套适配LoongArch的软件仓库和部分基础镜像,包括golang、openjdk、python、nginx、redis等常用软件的LoongArch版本。虽然数量远不如Docker Hub丰富,但覆盖了最常见的基础设施。
办法二:源码/包管理方式构建。这是最通用的兜底方案。以Redis为例,龙芯的Linux发行版源里通常带了redis的LoongArch版本,直接apt install redis,或者从源码编译。编译后和官方包行为一致。虽然这回归了传统安装方式,但你可以把它做成自定义镜像,以后分发就方便了:
FROM loong64/debian:bookworm-slim RUN apt update && apt install -y redis-server CMD ["redis-server", "--bind", "0.0.0.0"]办法三:用qemu-user模拟跨架构镜像。Docker支持在非原生架构上运行其他架构的镜像,原理是用qemu-user做用户态指令翻译。你可以启用buildx的cross-platform模拟:
docker run --privileged --rm tonistiigi/binfmt --install all docker pull --platform linux/arm64 mysql:8.0 docker run --platform linux/arm64 mysql:8.0但我要泼一盆冷水:这种方式在开发测试时可以应急,生产环境不推荐。性能损耗通常在30%到70%之间,有些计算密集的应用甚至可能差一个数量级。而且qemu模拟出来的环境偶尔会有诡异的兼容性问题——文件锁不可靠、glibc版本冲突、内存分配异常——排查起来非常痛苦。
7.4 龙芯Docker落地建议
在龙芯机器上用过一两个月之后,我的个人体会是:
- 不要期待"镜像拿来就能跑"。在龙芯上,Docker更像是一个"打包分发工具",而不是"软件超市"。你的重点应该放在构建自己的LoongArch镜像,而不是到处找现成的第三方镜像。
- 优先选与龙芯合作密切的Linux发行版,它们的源里已经适配了大多数常用软件,apt或者yum直接装好的二进制包,远比自己用qemu模拟x86镜像靠谱。
- 监控内存占用,龙芯机器目前常见于信创办公环境,服务器内存普遍不大,容器数量多了以后,swap频繁会导致性能雪崩。
docker stats要养成习惯看。 - 留一条传统安装的退路。有些核心数据库、任务调度组件,如果实在找不到LoongArch镜像,就老老实实装系统原生包。稳定压倒一切,别为了"必须用Docker"而强行折腾。
关于LoongArch架构的Docker生态,这几年其实在逐步完善,官方镜像列表里出现loong64的tag也越来越多。如果你是国产化平台的用户,建议多关注龙芯开源社区和厂商适配清单,信息更新速度远比Docker Hub的tag页面更快。
写在最后:给新手的几条操作建议
文章写到这,该聊的基本都聊了。最后分享几条我实际用下来的经验,希望对刚开始接触Docker的你有点帮助。
第一,不要背命令,要学会看帮助。docker run --help、docker compose --help、docker buildx --help,这些帮助信息写得比绝大多数教程都清楚。遇到不熟悉的参数,先查help,比网上搜答案快,而且不容易被过时信息误导。
第二,把常用启动命令固化成文件。不管是用docker-compose.yml还是简单的shell脚本,只要是你需要重复部署的环境,一定不要依赖"上次敲过的命令"。我在文章里反复强调Compose的价值,实际使用中,一份几十行的YAML文件,比一长串docker run参数直观得多,也方便版本管理。
第三,养成看日志的习惯。容器起不来、网络不通、数据同步失败,90%的问题都能在docker logs里找到线索。而且Docker的日志通常打印得很清楚,看到一个关键字,配合搜索引擎基本上能解决绝大多数问题。
第四,注意容器是临时的,数据卷才是永久的。这是Docker装软件最容易踩的坑——以为数据在容器里,结果容器一删,数据全没了。只要涉及数据库、配置文件、脚本,都给它挂上数据卷。
Docker真正降低了安装和维护软件的门槛,但前提是你理解了它的基本逻辑:镜像负责打包,容器负责运行,数据卷负责持久化,Compose负责编排。把这四个概念吃透,Docker就从一个"专门的工具"变成了你日常开发和管理服务器的基础能力。希望这篇文章能帮你少走一点弯路。