ARTICLE DETAIL

资讯详情

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

Docker 入门实战:从 hello-world 到容器化自己的服务,一篇吃透 6 个核心概念(Colima 环境实操)

Docker 入门实战:从 hello-world 到容器化自己的服务,一篇吃透 6 个核心概念(Colima 环境实操) 实测环境macOSApple Silicon /arm64、colima0.10.3、Docker29.7.2。系列说明本文是「Colima × Docker」系列的下篇所有命令在Colima提供的容器环境里执行上篇《Colima 零基础实战》教你装好并启动它。不过本篇讲的都是Docker 通用知识——换 Docker Desktop、OrbStack、Rancher 任何环境命令与结论完全一样放心读。开始前先花 10 秒确认环境Colima 在跑、docker 已接上它。colima status# 显示 running 即可dockercontextls# * 在 colima 行如果这两条没通过先回上篇把环境跑起来再回来看本文。一、先跑起来hello-world 与常用命令速查1.1 第一条容器Docker 世界有个传统第一条容器一定是 hello-world它是环境通不通的体检报告。dockerrun--rmhello-world正常机器会打印Hello from Docker! This message shows that your installation appears to be working correctly. To generate this message, Docker took the following steps: 1. The Docker client contacted the Docker daemon. 2. The daemon pulled the hello-world image from the Docker Hub. ...⚠️ 如果报i/o timeout/dial tcp ...:443: i/o timeout是拉镜像连不上 Docker Hub按上篇第六节配好镜像加速器再跑即可这不是操作错误。1.2 Docker 常用命令速查表入门收藏先给一张速查表垫底后面所有实战都离不开这几个命令。不用背用多了自然记住。命令作用备注docker run 镜像跑一个容器本地没有会自动拉取docker run -d --name web -p 8080:80 nginx后台运行 命名 端口映射最常用组合docker ps看运行中的容器-a连已停止的一起看docker images看本地镜像拉过的都在缓存里docker pull 镜像显式拉取镜像默认不用run 会自动拉docker exec -it 容器 bash进容器里敲命令排查问题常用docker logs 容器看容器日志排错第一步docker stop 容器停止容器不删数据docker rm 容器删除容器先 stop 或带-fdocker rmi 镜像删除镜像下次 run 会重拉docker system prune -a清所有闲置镜像/容器/网络数据卷默认保留小知识docker run没加--rm时容器停止后仍在docker ps -a可见需要手动docker rm加--rm则停止即删适合一次性验证。hello-world 就是典型的一次性容器所以都带--rm。二、实战1用 docker-compose 起一个 Nginx 静态站点光跑 hello-world 不过瘾来个真能用的。目标是起一个 Nginx访问http://localhost:8080能看到你自己的页面。顺便把 compose 编排、端口映射、目录挂载三个概念一起过了。2.1 建目录和文件mkdir-p~/colima-demo/htmlcd~/colima-demo写一个简单的首页html/index.html!doctypehtmlhtmllangzh-CNheadmetacharsetutf-8titleDocker Demo/title/headbodyh1Colima Docker 跑通了/h1p这是用 docker-compose 起的一个 Nginx 静态站点。/p/body/html写docker-compose.yml这就是服务的配方——声明用哪个镜像、映射哪个端口、挂哪个目录services:web:# 多架构镜像拉取走镜像加速器不直接连 Docker Hubimage:nginx:alpineports:-8080:80volumes:-./html:/usr/share/nginx/html:rorestart:unless-stopped三个字段各干一件事image指定现成镜像ports把容器 80 映射到宿主 8080volumes把本地html目录挂进容器:ro表示只读容器里改不了你的文件。2.2 起服务dockercompose up-dColima 默认网络模式下VM 的端口会自动转发到宿主机 localhost所以容器里80映射到宿主8080后浏览器直接开http://localhost:8080就能访问不用折腾 IP。2.3 验证打开浏览器访问http://localhost:8080看到上面的标题即成功。命令行也能查dockercomposepscurl-shttp://localhost:8080|head-52.4 清理养成好习惯dockercompose down# 停并删容器# 不想要这个 demo 了cd..rm-rf~/colima-demo三、Apple Silicon 专属坑镜像架构层面M 系列芯片跑容器绝大多数情况无感但遇到老镜像会踩架构坑。这一节专讲镜像的架构Colima VM 本身的架构选择见上篇第七节。优先用 arm64 原生镜像比如nginx:alpine多架构、python:3.12-slim都自带 arm64跑起来最快最省电。只有 amd64 的镜像用docker run --platform linux/amd64 镜像让 Colima 模拟跑默认开了 binfmt 模拟能跑但慢一点。如何确认镜像架构dockerimage inspect nginx:alpine--format{{.Architecture}}# 输出 amd64 或 arm64建议优先用多架构镜像现在主流镜像都提供 arm64实在没有再用--platform兜底。四、实战2把自己的服务容器化Python Flask 示例第二节用的是nginx:alpine——别人做好的镜像pull 即用。但你自己的本地服务没人发镜像得自己写 Dockerfile、自己 build。这一节用一个最小 Flask 应用完整走一遍本地代码 → 镜像 → 容器的全流程。这是全篇最有含金量的一节慢点读。核心认知image: xxx是用别人做好的镜像build: .是用当前目录的 Dockerfile 现做镜像。容器化自己的服务关键就在后者。整条本地代码 → 镜像 → 容器的链路画出来是这样4.1 准备项目文件建目录~/flask-demo写四个文件app.py最小 Flask 服务注意必须监听0.0.0.0否则容器外访问不到fromflaskimportFlask appFlask(__name__)app.route(/)defhello():return(h1Colima Docker 跑通了我的 Python 服务/h1p这是一个用 Dockerfile 自己构建镜像的 Flask 示例。/p)if__name____main__:app.run(host0.0.0.0,port5000)为什么必须监听0.0.0.0Flask 默认只监听127.0.0.1本机回环容器里这样写外部就访问不到0.0.0.0表示监听容器内所有网卡端口映射才能进来。requirements.txtflask3.0.3Dockerfile构建镜像的配方国内源写在 pip 安装那一步# 1. 基础镜像自带 Python 3.12 运行环境多架构Apple Silicon 原生支持 FROM python:3.12-slim # 2. 工作目录 WORKDIR /app # 3. 先拷依赖清单并安装利用层缓存改代码不会重装包 COPY requirements.txt . # 国内源用清华 PyPI 镜像避免直连 pypi.org 超时 RUN pip install --no-cache-dir -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple # 4. 再拷业务代码 COPY . . # 5. 声明容器监听端口仅声明真正对外靠 -p EXPOSE 5000 # 6. 启动命令 CMD [python, app.py]docker-compose.yml注意build: .而非image:services:web:# 关键用当前目录的 Dockerfile 构建镜像而不是 pull 现成镜像build:.image:flask-demoports:-8899:5000restart:unless-stopped4.2 构建并启动cd~/flask-demodockercompose up-d--build首次会拉python:3.12-slim基础镜像走配置的国内加速器再用清华源装 Flask。看到Successfully tagged flask-demo:latest和Container flask-demo-web-1 Started即成功。4.3 验证dockercomposeps# NAME IMAGE COMMAND SERVICE STATUS PORTS# flask-demo-web-1 flask-demo python app.py web Up 0.0.0.0:8899-5000/tcpcurl-shttp://localhost:8899# h1Colima Docker 跑通了我的 Python 服务/h1p这是一个用 Dockerfile 自己构建镜像的 Flask 示例。/p浏览器开http://localhost:8899就能看到页面。4.4 改动即所见体验闭环直接改app.py里的文字保存然后dockercompose up-d--build刷新浏览器即可看到新内容——这就是改代码 → 重建镜像 → 重新运行的开发闭环。第一次体会这种体验的人往往会被它圈粉。4.5 写好 Dockerfile 的几个要点基础镜像选带运行时的python:3.12-slim、node:20-alpine等别从ubuntu裸机自己装。依赖先于代码 COPY先COPY requirements.txt装完依赖再COPY . .改业务代码时不用重装依赖Docker 层缓存。EXPOSE只是声明真正对外靠docker run -p或 compose 的ports。配置/数据用 volume 挂别写死进镜像镜像应是不可变的。国内源全覆盖基础镜像走 registry 加速器pip/npm显式写国内镜像如上面清华源。和第二节对照唯一差别就是image: nginx:alpine换成了build: .。理解这一处你就掌握了部署自己的服务到 Docker的本质。五、镜像拉取后会持久化吗本地缓存机制很多小白担心“每次docker run都要联网去 Docker Hub 拉一遍那岂不是又慢又费流量” 答案是不会。Docker 的设计就是本地优先拉过的镜像会持久化缓存默认不重复拉。这一节把机制讲透你就彻底放心了。5.1 直接结论拉过的镜像默认持久化存在本地之后docker run直接用缓存不会重复联网拉取。只有你主动要求更新、或本地缓存被删才会再去拉。5.2 实机证据你本机现在的缓存在本文写作时你的机器上已经缓存着这些镜像执行docker images可见REPOSITORY TAG SIZE flask-demo latest 223MB python 3.12-slim 205MB nginx alpine 93.6MB hello-world latest 22.6kB它们已经在本地不需要每次重新拉。你第一次跑docker run --rm hello-world时打印过Unable to find image hello-world:latest locally本地没有→去拉第二次就不会有这行了——因为已在缓存里。5.3 机制拆解docker pull/ 首次docker run时守护进程去仓库走配好的国内镜像源下载镜像各层解压后持久化到本地的 image store——在 Colima 场景下就是存在 Colima 那台 VM 的虚拟磁盘里不是你 Mac 的某个普通文件夹直接可见之后你再docker run nginx:alpine守护进程发现本地已有同名同 tag 的镜像直接启动容器跳过下载。镜像只存一份多个容器共享同一镜像层不会翻倍占用。把首次拉取和再次使用两条路径画到一张图上更直观5.4 什么时候会再去拉对照表你的操作会不会重新拉取说明直接docker run nginx:alpine本地已有不会用本地缓存秒起显式docker pull nginx:alpine会主动要最新版docker compose up本地已有不会同上compose 里写pull_policy: always会故意强制每次更新docker rmi nginx:alpine后 run会本地缓存被删colima delete后重建 VM会整个 VM 磁盘清空镜像全丢colima stop/colima restart不会镜像在 VM 磁盘里重启不丢5.5 Colima 用户必知的两点镜像存哪在 Colima 的 VM 里不在 macOS 文件系统直接可见。colima stop关机或colima restart重启都不会丢镜像但colima delete删虚拟机会连镜像一起清空下次docker run要重新拉。磁盘占用用docker system df查看。本文写作时 4 个镜像实际占用约319 MB。注意docker images的 SIZE 列是完整大小flask-demo 与 python:3.12-slim 共享基础层会被重复计入四行相加约 522 MB而docker system df是去重后的真实磁盘占用。两者对不上是正常的以docker system df为准。镜像只存一份多个容器共享层不翻倍。5.6 常用维护命令dockerimages# 看本地有哪些镜像dockersystemdf# 看镜像/容器/卷占了多少空间dockerimage prune# 删悬空镜像没被任何容器用的中间层dockerimagerm名称# 手动删某个镜像下次 run 会重拉记忆点image:拉一次永久缓存只有显式 pull / 手动删 / 删 VM这三种情况才会再拉。Docker 的设计就是本地优先不存在每次 run 都联网这回事。六、不同服务能用相同端口吗端口冲突与推荐方案很多小白在起第二个容器时会撞上Bind for 0.0.0.0:xxxx failed: port is already allocated。这一节讲清端口的两层规则并给出多服务共存的推荐方案。6.1 直接结论分两层看层能不能相同说明容器内部端口-p里:后面那个可以每个容器是独立的网络命名空间互不干扰宿主机映射端口-p里:前面那个不能宿主机端口是稀缺资源同一时刻只能一个进程占用-p 8080:80的含义是宿主机的 8080→容器的 80。宿主机Colima VM经localhost转发到你的 Mac的 8080 一旦被占别的容器再绑 8080 就冲突。把这两层规则和多服务共存的三种推荐方案画到一张图里6.2 实机证据同一宿主端口必冲突本文写作时实机跑了两个容器都绑宿主 9999dockerrun-d--nameptest1-p9999:80 nginx:alpine# 成功dockerrun-d--nameptest2-p9999:80 nginx:alpine# 失败第二个直接报错docker: Error response from daemon: ... Bind for 0.0.0.0:9999 failed: port is already allocateddocker ps显示只有ptest1占着0.0.0.0:9999-80/tcp。测试容器已清理。6.3 对照你的两个 demo端口规则实感服务映射能否共存Nginx第二节 demo8080:80宿主 8080 已占Flask第四节 demo8899:5000宿主 8899 空闲 → 共存若 Flask 也设8080:50008080:5000宿主 8080 冲突起不来注意即使容器内部端口不同80 vs 5000只要宿主侧都是 8080就冲突。冲突看的是宿主侧那个数字。6.4 推荐方案多服务共存怎么排端口方案 A推荐多服务 / 生产反向代理做统一入口不想记一堆端口、希望都走80或8080正确做法不是硬绑同一个宿主端口而是加一个网关容器做路由起一个 Nginx / Caddy / Traefik 容器独占80或8080其他业务服务不映射宿主端口只在容器内监听或挂到同一个 Docker 网络网关按域名 / 路径把请求转发给对应容器。这样外部只看到一个端口内部由网关分流。服务较多时可用 Traefik 自动服务发现避免手动维护转发规则。方案 B省心临时 / 单机让 Docker 随机分配宿主端口只写容器端口宿主侧由 Docker 随机挑一个空闲端口彻底杜绝冲突services:web:image:nginx:alpineports:-80# 只写容器端口宿主侧由 Docker 随机分配启动后docker port 容器名看实际分到了哪个宿主端口docker compose ps会显示成0.0.0.0:49153-80/tcp这种高位随机口。方案 C最直观简单并存手动错开宿主端口如本文 demoNginx 用8080、Flask 用8899各自独立、互不干扰适合服务少、临时演示。6.5 记忆点容器内部端口随便重复宿主映射端口必须唯一。冲突只看宿主侧那个数字多服务想共用入口用反向代理别硬抢同一个宿主端口。七、常见故障排查表Docker 相关现象原因解决docker: command not found没装 docker 客户端brew install docker docker-composeCannot connect to the Docker daemonColima 没启动 / context 没切colima start或docker context use colima拉镜像i/o timeout连不上 Docker Hub按上篇第六节配镜像加速浏览器打不开localhost:端口容器没起 / 端口映射错docker ps看端口确认ports写对容器里访问不到自己的服务服务没监听0.0.0.0改监听地址如 Flask 写host0.0.0.0起第二个容器报port is already allocated宿主端口被占换宿主端口或改用随机端口 / 反向代理磁盘爆满镜像/卷堆积docker system prune -a或调大--disk后colima delete重建总结你现在已经掌握了跑通容器docker run --rm hello-world 常用命令速查。真实战现成镜像docker-compose 起 Nginx浏览器访问localhost:8080。真实战自建镜像用 Dockerfile 把自己的服务容器化Flask 示例build: .vsimage:的区别是核心。Apple Silicon 架构优先多架构镜像只有 amd64 时用--platform linux/amd64。镜像持久化拉过的镜像缓存在本地Colima VM 磁盘里默认不重复拉只有显式pull、手动rmi、colima delete才会重建。端口规则容器内部端口可重复宿主映射端口必须唯一多服务共存用反向代理或随机端口别硬抢同一宿主端口。如果这篇攻略帮你少踩了坑欢迎点赞、收藏、留言告诉我你还想看哪块进阶内容比如 k3s 实战、多架构镜像构建、CI 里用 Colima。我们下篇见。附术语注解Dockerfile构建镜像的配方文件描述基础镜像、依赖安装、代码拷贝与启动命令docker build依据它生成镜像。多架构镜像multi-arch image同一镜像名同时提供 arm64 和 amd64 版本Docker 按当前架构自动选如nginx:alpine。--platform指定运行镜像的架构如linux/amd64配合 binfmt/Rosetta 在 Apple Silicon 上跑 x86 镜像。反向代理reverse proxy位于客户端与多个后端服务之间的转发层如 Nginx / Caddy / Traefik对外暴露单一端口按域名或路径把请求转发到内部不同服务是多服务共用入口端口的推荐方案。image store本地镜像仓库Docker 存放已拉取 / 已构建镜像的地方Colima 场景下位于 VM 虚拟磁盘内多个容器共享其中的镜像层不翻倍占用。pull_policycompose 的拉取策略always表示每次启动都强制重新拉取镜像默认不设置则本地优先不重复拉。
返回列表